C#知识(4)
1.委托
本来我是想先聊聊事件的,但是没有委托的事件是不完整的,所以我们还是先聊一下委托,
如果你和我一样是C++和C#双开的,你一定知道C++里面有一个概念叫做指针,而指针中有一类比较特殊的叫做函数指针,函数指针的作用其实就是让一个函数变成一个变量,让函数变成方法的参数,从而指定方法根据不同情况使用不同函数。
其实C#中委托和函数指针的作用几乎一模一样,,又或者说就是一样的。先来看一下用法吧。
using System;
class program
{
public static void Ashow(string a)
{
Console.WriteLine(a+"我是A");
}
public static void Bshow(string b)
{
Console.WriteLine(b+"我是B");
}
public static void Cshow(string c)
{
Console.WriteLine(c+"我是C");
}
public delegate void Show(string s);
public static void Getshow(Show a,string s)
{
a(s);
//a.Invoke(s); //这样写也行
}
public static void Main(string[] argv)
{
string a = "hhh";
Show oneshow = Ashow; //可以直接赋值
Show twoshow = new Show(Bshow); //也可以new了之后再将函数名按照参数传进去
Show threeshow = new Show(Cshow);
Getshow(oneshow,a);
Getshow(twoshow,a);
Getshow(threeshow,a);
Show allshow = null;
allshow += oneshow; //+=后面可以跟方法名
allshow += twoshow;
allshow += threeshow;
Getshow(allshow,a);
}
}
委托的使用非常简单,声明的时候使用一个delegate关键词就行。使用的话可以把实例出来的委托名直接作为函数名使用。也可作为参数传给其他的方法。
接下来我们讨论以下委托的深层次的东西(来源于《clr via C#》)
使用起来简答的东西内部的实现细节就会越复杂,为了让委托好用,编译器和clr为我们干了太多事了(感动)(如果不知到clr是什么的,我回头会写,你可以先当它是C#虚拟机)
当我们用以下语句定义一个委托时
public delegate void Show(string s);
编译器会将这行代码定义成下面这样一个类
internal class Show:System.MulticastDelegate
{
public Show(object target, IntPtr method);
public virtual void Invoke(Int32 value);
public virtual IAsyncResult BeginInvoke(Int32 value, AsyncCallback callback, Object @object);
public virtual voidEndInvoke(AsyncCallback result);
}
BeginInvoke和EndInvoke先不谈,先聊一下构造器和Invoke函数
构造器,其实就是C++的构造函数,我们首先注意到的是它的两个参数,既然构造函数有参数,自然是要用这些函数来初始化类中的成员的,所有的委托都是继承于System.MulticastDelegate这个类,而System.MulticastDelegate这个类又是派生自System.Delegate类,这其中有一些历史原因,这里就不展开说了,反正就是继承下来的成员有三个比较重要的:
所以构造器的两个参数分别是target,methodPtr。
最后一个字段invocationList则是在我们像allshow那样将一堆方法构造成一个委托链时会用到,他就像一个链表分别去装构造这个委托的所有方法或委托。
接下来是Invoke方法,这个方法在委托被定义的时候被定义,通过调用target和methodPtr字段在指定的对象上调用包装好的回调方法。所以通过委托调用方法时,其实就是在调用委托类的Invoke方法,所以你直接在编程的时候就直接写成a.Invoke(s)也可以。
最后就是在System.Delegate类中有个方法可以直接取得invocationList中的值。比如下面这个例子就是其中的一种用法。
Delegate[] array = allshow.GetInvocationList();
foreach (var every in array)
{
Console.WriteLine(every.Method.Name);
}