委托
委托:委托是一种安全地封装方法的引用类型,他是面向对象的、类型安全的和保险的,它可以代理一个或是多个方法,或是代码块执行,由于是引用类型,它保存的不是实际值,而是保存对存储在托管堆中的对象的引用,即对函数的引用。
构造委托对象的方法:
命名方法:使用命名方法构造的委托可以封装静态方法或实例方法(当然定义定义委托的时候不能用static修饰,静态方法不能调用实例化方法),命名方法代理的是方法。
public delegate void SampleDelegate(string message); public static void SampleDelegateMethod(string message) { Console.WriteLine("SampleDelegateMethod:" + message); } SampleDelegate d1 =new SampleDelegate(SampleDelegateMethod); //可以简写成 SampleDelegate d1 = SampleDelegateMethod; d1("chentaihan");
匿名方法:匿名方法代理的是一段代码块,使用匿名方法,则不必创建单独的方法,因此减少了实例化委托所需的编码系统开销。
SampleDelegate d2 = delegate(string message) { Console.WriteLine(message); }; d2("chentaihan");
委托中的协变与逆变
协变实例如下
public class Animal { public Animal(string name) { this.Name = name; } protected string Name; public virtual void ShowName() { Console.WriteLine("Animal:" + Name); } }; public class Cat : Animal { public Cat(string name) : base(name) { } public override void ShowName() { Console.WriteLine("Cat:" + Name); } } public delegate Animal DelegateAnimalXB(string name); public class DelegateXB { public static Animal CreateAnimal(string name) { return new Animal(name); } public static Cat CreateCat(string name) { return new Cat(name); } public static void Test() { DelegateAnimalXB d1 = CreateAnimal; d1("Animal").ShowName();//Animal:Animal DelegateAnimalXB d2 = CreateCat; d2("Cat").ShowName();//Cat:Cat } }
委托协变讲的是定义委托是返回类型的多态,我觉得重点根本不在委托,这其实还是一个类型转换的问题,定义委托时返回类型未Animal,你返回他的之类Cat,没有问题啊,编译器帮你隐式类型转换啊,就这样。
委托逆变实例如下:
public class MyEventArgs : EventArgs { public MyEventArgs(){} } public class DelegateNB { public delegate void Handler(EventArgs e); public event Handler eventHandler; public void Test(EventArgs e) { eventHandler(e); } } static void Main(string[] args) { DelegateNB nb = new DelegateNB(); nb.eventHandler += new DelegateNB.Handler(Test); nb.Test(new MyEventArgs()); Console.Read(); } public static void Test(EventArgs e) { Console.WriteLine(e.ToString()); } }
委托的逆变看上去实现了参数的多态,定义委托的时候,参数为EventArgs,而传进去的却是一个MyEventArgs,但是定义其他类型的参数,使用多态的方式传参却编译通过不了,只能是EventArgs及其之类,为什么是这样呢,俺也不知道,只知道事件代理的时候,定义委托的时候参数绝对是(object sender,EventArgs e),微软只用定义这一个事件,他就能委托很多类型的事件,如mouseup,mousedown,keyup等一堆类似的事件,正 因为定义委托的时候参数类型未EventArgs,所以你在写事件方法的时候参数为EventArgs或是相关的事件类(肯定也是EventArgs的之类)都是可以的。如文本框的KeyDown事件参数为KeyEventArgs,你用EventArgs是没有问题的,因为委托定义的时候参数就是EventArgs吗,当然用EventArgs没有会失去KeyEventArgs自带的属性和方法,反过来说如果我们不需要这些特有的属性和方法,用EventArgs会更好,杀鸡焉用宰牛刀。
泛型委托
泛型委托就会泛型跟委托的结合,根本不是什么新东西,只要你会泛型,会用委托,你就知道怎么使用泛型委托。泛型委托其实就是编译器动态的帮你定义一组委托,在你要用得时候才定义,不用就不定义,而且每种类型的委托只定义一次。泛型说白了就是编译器帮你写代码,当然使用他的确是减少了类型转换。
简单实例如下:
public class DelegateGeneric { public delegate void Del<T>(T item); public static void f1(double i) { Console.WriteLine(i); } public static void Test() { Del<double> d1 = f1; d1(1);//代理方法f1(double i),输出:1 } }
委托不能重载,即委托名称相同,参数类型,个数不同。构造委托的时候,根本不管参数,当然也就不知道你要构造的是哪个委托。
委托不支持多态,正因为重载的存在导致委托不能支持多态。
public class A { } public class B : A { } public class DelegateDT { public delegate void DelegateFun(A a); public static void DelegateA(A a) { Console.WriteLine("DelegateA"); } public static void DelegateA(B a) { Console.WriteLine("DelegateB"); } public static void Test() { DelegateFun d1 = DelegateA; d1(new B()); } }
这里其实调用的是方法DelegateA(A a),并不是DelegateA(B a),要是支持多态的话,他根本就不知道调用哪个方法,还是因为多态,你传进来一个对象B,正好有一个方法所需的参数是B的父类A,所以编译器自动将B隐式转换成A,然后调用方法DelegateA(A a),如果没有这个方法,编译是通不过的。多态不就是编译器帮我们寻找最合适的方法吗,如果没找到,就隐式转换,看有没有合适的方法,如果没有,编译出错。
作者:陈太汉