.net 中的委托(delegate)的使用和原理
.net中的委托,我个人认为很类似于C++ 中的函数指针。你定义一个代理,然后注册函数到这个代理中即可使用。
通过下面的例子来讲解.net中委托的使用using System;
using System.IO;
using System.Windows.Forms;
class Set
{
private Object[] items;
//构造器。给对象数组进行初始化
public Set(Int32 numItems)
{
items = new Object[numItems];
for(Int32 i = 0; i < numItems; i++)
{
items[i] = i;
}
}
//定义一个FeedBack委托类
public delegate void FeedBack(Object value, Int32 item; Int32 numItems);
public void ProcessItems(FeedBack feedback)
{
for(Int32 i = 0; i < items.Length; items++)
{
if(feedback!=null)
{
//如果指定有回调函数,则调用它们
feedback(items[item]; item + 1; items.Length);
}
}
}
}
//定义一个应用类来应用委托
class App
{
public static void main()
{
StaticCallBack();
InstanceCallBack();
}
public static void StaticCallBack()
{
//设定含有5个Object的Set对象
Set setOfItem = new Set[5];
//处理items元素,但不给任何反馈
setOfItem.ProcessItems(null); -----------1
Console.WriteLine();
//处理items元素,并将反馈输出到控制台上
setOfItem.ProcessItems(new Set.FeedBack(App.FeedBackToConsole));//注册代理---2
Console.WriteLine();
//处理items元素,并将反馈输出到消息框上
setOfItem.ProcessItems(new Set.FeedBack(App.FeedBackToMsgBox));//注册代理 ---3
Console.WriteLine();
//处理items元素,并将反馈同时输出到控制台和消息框中
FeedBack fb = null;
fb += new Set.FeedBack(App.FeedBackToConsole);
fb += new Set.FeedBack(App.FeedBackToMsgBox);
setOfItems.ProcessItems(fb); --------4
Console.WriteLine();
}
static void FeedBackToConsole(Object value, Int32 item; Int32 numItems)
{
Console.WriteLine(String.Format("Processing item{0} of {1}:{2}",item, numItems, value));
}
static void FeedBackToConsole(Object value, Int32 item; Int32 numItems)
{
MessageBox.Show(String.Format("Processing item{0} of {1}:{2}",item, numItems, value));
}
static void InstanceCallBack()
{
//设定含有5个Object的Set对象
Set setOfItem = new Set[5];
//处理items元素,并将反馈输出到一个文件中
App appobj = new App();
setOfItems.ProcessItem(new Set.FeedBack(appobj.FeedBackToFile)); -------5
Console.WriteLine();
}
public void FeedBackToFile(Object value, Int32 item; Int32 numItems)
{
StreamWriter sw = new StreamWriter("status",true);
sw.WriteLine(String.Format("Processing item{0} of {1}:{2}",item, numItems, value));
sw.Close();
}
}
在上面的程序中,包括5此对FeedBack委托的使用,也就是调用Set类的ProcessItem静态方法。第一次ProcessItem的参数为空,表示不使用委托。
第二次调用ProcessItem方法时,它首先构造了一个新的Set.FeedBack委托对象(至于这个对象的具体东西,会在后面有解释)。在将FeedBackToConsole方法作为参数传递给FeedBack构造器,并将返回值作为ProcessItem的参数传递过去。
第三次调用和第二次差不多,只是调用的函数不同罢了。
第四次调用为我们展示了怎样把委托对象链接成一个委托链。C#中的+= 操作符用来把委托对象追加到fb引用的委托对象链表上。
第五次调用的不同之处在于,传递的方法是一个实例方法而不是一个静态方法。
下面我们来揭开委托神秘的面纱:
再类看一遍下面这行代码:
public delegate void FeedBack(Object value, Int32 item; Int32 numItems);
当编译器遇到这行代码时,它会产生如下面所示的一个完整的类定义;
public class FeedBack : MulticastDelegate
{
//构造器
public FeedBack(Object target, Int32 methodPtr);
//下面的方法和源代码中指定的原型相同
public void virtual Invoke(Object value, Int32 item; Int32 numItems);
//下面两个方法允许我们对委托进行异步回调
public virtual IAsyncResult BeginInvoke(Object value, Int32 item; Int32 numItems ,AsyncCallback callback, Object object);
public virtual void EndInvoke(IAsyncResult result);
}
我们只关注构造器和Invoke方法。
构造器方法中的target存放的是方法对象的引用,如App.FeedBackToFile中的App,methodPtr存放的是一个特殊的标志方法的Int32值。这些就可以准确的标识一个方法。Invoke方法会被自动调用。