zoukankan      html  css  js  c++  java
  • 泛型与委托

    小结:

    一、泛型【代码重用/算法重用】

    1.优点:

    a.源代码保护:使用泛型算法时不需要访问算法的源代码

    b.类型安全性

    c.更加清晰的代码

    d.更好的性能:CLR不再需要执行任何装箱、拆箱操作

    2.常用的泛型集合类/泛型容器

    a.List<T>
    b.Dictionary<TKey,TValue>
    c.Stack<T>
    d.Queue<T>

    3.代码爆炸

    使用泛型类型参数的一个方法在进行JIT编译时,CLR获取方法的IL,替换指定的类型参数,然后针对那个方法在指定数据类型上的操作创建特有的本地代码。这是泛型的主要特性之一,然而,这样做有一个缺点:CLR要为每种不同的方法/类型组合生成本地代码。将这个现象称为“代码爆炸”,最终会造成应用程序的工作集显著增大,从而损害性能。

    幸运的是,CLR内建了一些优化措施,能够缓解代码爆炸:

    a.假如为一个特定的类型实参调用了一个方法,以后再次使用相同的类型实参来调用这个方法,那么CLR只会为这种方法/类型组合编译一次代码。
    b.CLR认为所有引用类型实参都是完全相同的,所以代码能够共享。例如,CLR为List<String>的方法编译的代码可以用于List<Stream>的方法。

    ----但对于值类型,CLR必须专门为那个值类型生成本地代码,即使两个值类型具有相同的大小(比如Int32和UInt32两者都为32位),CLR仍然无法共享代码。

    二、委托

    1.协变与反协变
    将一个方法绑定到一个委托时,C#和CLR都允许引用类型的协变与反协变

    协变:指的是一个方法的返回类型可以是委托的返回类型的一个派生类型
    反协变:指的是一个方法的参数类型可以是委托的参数类型的基类型

    例子: public delegate Object TestCallBack(String s);

             public static String SomeMethod(Object st) {    return "hi"; }

             TestCallBack call = SomeMethod("tty");//这是允许的

    ----协变与反协变只能用于引用类型,不能用于值类型或void,所以不能把下面的方法绑定到TestCallBack委托:

         public static Int32 SomeMethod(Object st);

    2.委托的本质
    委托本质上是一个类,该类中含一个构造函数、Invoke、BeginInvoke和EndInvoke四个方法,形成的IL Code如下图所示:

    构造函数含两个参数,一个是对象的引用,另一个是引用该对象中的回调方法的一个整数
    所有委托都继承自System.MulticastDelegate, System.MulticastDelegate类继承自System.Delegate, System.Delegate继承自System.Object。

    a. 委托定义了方法的类型,使得可以将方法当作另一个方法的参数进行传递,这种将方法动态的赋给参数的做法,可以避免在程序中大量使用If---Else(Switch)语句,同时使得程序具有更好的可扩展性

    b. 可以将多个方法绑定到同一个委托变量身上,当调用此变量时,可以依次调用所有绑定的方法

    3.委托链
    C#编译器为委托类型的实例提供了运算符+=和-=重载,这两个运算符分别调用Delegate.Combine和Delegate.Remove,从而简化了源代码

    在创建好一个委托对象链时,调用该委托后会自动调用委托链上的所有对象的方法,带来方便之外也有它的局限性:

    a.除最后一个回调方法的返回值之处,其他回调方法的返回值都会被丢弃
    b.如果被调用的委托中有一个抛出了异常或阻塞了相当长一段时间,就会停止调用后续所有对象的方法

    有些时候我们需要对链上的每个对象的方法控制的更多,Delegate中定义了一个获取委托数组的虚方法,如下:

    public abstract class Delegate : ICloneable, ISerializable
    {
        public virtual Delegate[] GetInvocationList();
        ...
    }
    
    public abstract class MulticastDelegate : Delegate
    {
        public override sealed Delegate[] GetInvocationList();
        ...
    }

    这样,当我们创建一个委托链时,我们就可以通过GetInvocationList方法获取该链上的每一个委托对象,然后就可以为每个对象中的方法加上我们自己的控制了
    一个简单例子:

        public delegate void Change(Int32 x);
        class Program
        {
            public void Add1(Int32 x1)
            {
                num += x1;
            }
    
            public void Add2(Int32 x2)
            {
                num += x2;
            }
    
            public void Add3(Int32 x3)
            {
                num += x3;
            }
        }
    
    调用:
                Program p = new Program();
                Change cal = null;//声明一个空委托
    
                cal = p.Add1;
                cal += p.Add2;
                cal += p.Add3;
                
                if (cal == null)
                {
                    return;
                }
                Delegate[] delist = cal.GetInvocationList();
    
                foreach (Change item in delist)//可以获取每个回调方法的返回值了
                {
                    //针对每个委托对象的控制代码
                    try
                    {
                        ...
                    }
                    catch(InvalidOperationException e)
                    {
                        ...
                    }
                }
  • 相关阅读:
    Transfer: Javascript实现网页水印(非图片水印)
    VirtualPathUtility class from MSDN
    深入理解Flink 系统内部消息传递的exactly once语义
    深入理解Flink EndtoEnd ExactlyOnce语义
    深入理解Flink Metrics的内部结构
    深度优化sql 查询, 提升性能一百倍是什么概念?
    asp.net mvc+asp.net webform: a way of RIA + RAD
    使用scheduled task, 让电脑音乐伴你入眠
    A small breaking change in IE8 causing big pain in the ass: the default type of button element
    tsql 和 clr 的性能实测比对
  • 原文地址:https://www.cnblogs.com/notebook2011/p/2936775.html
Copyright © 2011-2022 走看看