c# delegate和event的使用说明
作者:林新发
delegate是什么
委托(delegate) 是存有对某个方法的引用的一种引用类型变量,引用可在运行时被改变。如果不好理解,可以把委托理解成为函数指针,但它们是有区别的。
delegate和C++中的函数指针:
函数指针只能指向静态函数,而delegate既可以引用静态函数,又可以引用非静态成员函数。在引 用非静态成员函数时,delegate不但保存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。
其次,与函数指针相 比,delegate是面向对象、类型安全、可靠的受控(managed)对象。也就是说,runtime能够保证delegate指向一个有效的方法, 你无须担心delegate会指向无效地址或者越界地址。
实例化委托:一旦声明了委托类型,委托类型必须要通过new关键字来创建(相当于面向对象中的实例化一个对象),当创建委托时,传递到new语句中的参数就像方法的调用一样书写, 但是不带参数。
// 委托的声明 public delegate void PrintSting(string s); //实例化委托 PrintSting ps=new PrintString(WriteToScreen);
匿名方法:
本来委托定义(声明)好之后,还得再单独定义委托需要使用的方法。比如你定义了一个计算器的委托, 你还需要重新写计算加减乘除的方法了来供计算器委托来使用。这时候我们就想到了匿名方法。
用匿名方法就不需要再单独写加减乘除这些方法了,只需要在匿名方法的方法体内实现这些逻辑就好了。例子如下:
delegate int calculator(int x, int y); //委托类型 static void Main(string[] args) { //创建委托对象(确定与哪些方法进行绑定),委托实例名=new 委托名(某个类的方法,本例与加法向绑定 calculator Adding =delegate( int x, int y){ return x+y; }; calculator Moveing = delegate(int x, int y){ return x - y; }; calculator Multiply = delegate(int x, int y) { return x * y; }; calculator Divide = delegate(int x, int y) { return x / y; }; Adding(4, 4);//8 Moveing(4, 4);//0 Multiply(4, 4);//16 Divide(4, 4);//1 }
event是什么
我们可以把事件编程简单地分成两个部分:事件发生的类(发布器:publisher)和事件接收处理的类(订阅器:subscriber)。事件使用 发布-订阅(publisher-subscriber) 模型。
事件发生的类就是说在这个类中触发了一个事件,但这个类并不知道哪个个对象或方法将会加收到并处理它触发的事件。所需要的是在发送方和接收方之间存在一个媒介。
这个媒介在.NET Framework中就是委托(delegate)。
在事件接收处理的类中,我们需要有一个处理事件的方法。
public class A { public delegate void EventHandler(object sender); public event EventHandler a; public void Run() { Console.WriteLine("Trigger an event."); a(this); } } class B { public B(A a) { a.a += new A.EventHandler(this.b); } private void b(object sender) { Console.WriteLine("Received and handled an event." ); Console.Read(); } }
event和delegate的差异
event是一种特殊的delegate。同为public类型,对于delegate,我们在定义它的类外,不仅可以采用 += 和-=的运算符号,还可随时调用;但是对于event,在类外只能采用 += 和-=的运算符号,不能调用,也就是event把它本身的invoke函数和括号调用的函数变成拥有这个event类的私有函数。
event
event只能被本类调用,其他的即使该类的派生类也不行,如果非要调用类内部的event,可以先声明一个方法,在该方法中调用event。
Action
Action是一个泛型的委托,其内部即使用delegate去实现,当普通的delegate定义的参数与Action个数、类型一致时,两者实现的功能是一样的。只是Action的方式更加简洁、规范。
Action与delegate更重要的一个区别在于泛型,即Action的内部使用了泛型+委托,且泛型的方法的参数个数可扩展到16个。微软.net corefx中定义的Action内部代码如下:
namespace System { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。