那么先讲讲委托吧,委托是一种定义方法签名的类型,当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联。 您可以通过委托实例调用方法。
使用委托的一个好处就是像操作变量一样操作一个方法。
下面是委托的一些特点:
public delegate void MyDelegate(object obj);
这行代码就是用来声明一个委托类型。再看如下代码:
class Program { public delegate void MyDelegate(object obj); static void Main(string[] args) { // 在这儿,把MyDelegate看做一个类(其实它就是一个类class) // 下面这行代码和声明一个对象一模一样,因为mydelegate它就是一个对象 // 注意Method1的原型和MyDelegte一致才行(逆变和协变的内容在后面) // 其实下面这行代码可以简写为:MyDelegate mydelegate = Method1; MyDelegate mydelegate = new MyDelegate(Method1); // 下面这行代码和mydelegate.Invoke(new object());没有任何区别! // 这行代码的目的就是执行Method1方法 mydelegate(new object()); } // 方法 i public static void Method1(object o) { Console.WriteLine("Method1 Calling"); } }
运行输入结果:Method1 Calling.
那么委托时如何像一个参数一样传给别的方法呢?下面这段代码用委托回调的方式开求1~100的和:
class Program { public delegate void CallBack(int number); static void Main(string[] args) { // 这个函数调用后,将输出1~100的和 Execute(100, Sum); } private static void Execute(int param, CallBack callBack) { if (callBack != null) { // 在这个地方调用callBack委托 callBack(param); } } private static void Sum(int number) { int sum = 0; for (int i = 0; i <= number; i++) { sum += i; } // 为了做演示,就暂且用这种最复杂的方法求和吧 Console.WriteLine("1~" + number + "的和为" + sum); } }
程序运行结果:1~100的和为5050。
那么就有人要说了,我像调用一次Execute方法,求出1~100的和之外还求出他们的所有质数之和怎么做呢,那么就可以使用委托将多个方法链接到一起了:
class Program { public delegate void CallBack(int number); static void Main(string[] args) { // 这个函数调用后,将输出1~100的和还有1~100之间质数的和 CallBack linkDelegate = Sum; // 使用+=运算符,将2个方法链接一起 linkDelegate += SumOfPrimeNumber; Execute(100, linkDelegate); } private static void Execute(int param, CallBack callBack) { if (callBack != null) { // 在这个地方调用callBack委托 callBack(param); } } private static void Sum(int number) { int sum = 0; for (int i = 0; i <= number; i++) { sum += i; } // 为了做演示,就暂且用这种最复杂的方法求和吧 Console.WriteLine("1~" + number + "的和为" + sum); } private static void SumOfPrimeNumber(int number) { int sum = 0; for (int i = 0; i <= number; i++) { if (IsPrime(i)) { sum += i; } } Console.WriteLine("1~" + number + "之间的所有质数的和为" + sum); } // 判断一个数字是否为质数 private static bool IsPrime(int n) { for (int i = 2; i * i <= n; i++) { if (n % i == 0) { return false; } } return true; } }
这段代码输出的结果为:1~100的和为5050。1~100之间的所有质数的和为1061。
class Program { public delegate void Contravariance(string str); static void Main(string[] args) { Contravariance md = Method1; md("Contravariance"); } static void Method1(object obj) { Console.WriteLine(obj + " Method1 Calling"); } }
class Program { public delegate void Contravariance(int str); static void Main(string[] args) { // 注意下面这行代码,虽然int是object的派生类型,但是下面这行代码还是会导致编译不过,因为逆变和协变对值类型不起作用(int为值类型) Contravariance md = Method1; md(4); } static void Method1(object obj) { Console.WriteLine(obj + " Method1 Calling"); } }上述代码是无法通过编译的,在使用逆变和协变中是都不支持值类型的。
同理,下面这个是逆变的例子:
class Program { public delegate object Convariance(); static void Main(string[] args) { // 虽然Convariance委托定义的类型返回值和Method1不一致,但是这段代码是可以正常运行的 Convariance md = Method1; md(); } static string Method1() { return "Method1"; } }
public delegate void TryCode(object userData); public delegate void WaitCallback(object state); public delegate void TimerCallback(object state); public delegate void ParameterizedThreadStart(object obj);发现这些委托定义的共同点了吗?是不是都一模一样?事实上在.NET Framework上可以使用委托泛型,上面所有的泛型其实都可以仅使用:
public delegate void Action<in T>(T obj);这一个委托定义来实现就可以了。在System命名空间下有这种多达17个Action委托(这儿使用in关键字表示委托类型支持逆变):
public delegate void Action(); public delegate void Action<in T1>(T1 arg1); public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2); ...
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);同样的System命名空间下也有17个Func的委托(使用out关键字表示委托泛型支持协变):
public delegate TResult Func<out TResult>(); public delegate TResult Func<in T1, out TResult>(T1 arg1); public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2); ...
我们再看如下一行代码:
internal delegate void Feedback(int value);其实它被编译后,看起来像如下一个完整的类:
internal class Feedback : System.MulticastDelegate { // 构造方法 public Feedback(object obj, IntPtr method); // 这个方法的原型和委托定义的一模一样 public virtual void Invoke(int value); // 一下方法实现了对回调方法的异步调用 public virtual IAsyncResult BeginInvoke(int value, AsyncCallback callback, Object obj); public virtual void EndInvoke(IAsyncResult result); }
本文内容就讲到这里了,谢谢各位。
原文地址:http://blog.csdn.net/lilacflower/article/details/44926901