委托构造原理浅析
委托是一种可用于封装命名或匿名方法的引用类型。委托类似于 C++ 中的函数指针;但是,委托是类型安全和可靠的。
本文将对委托的实现机制进行简单的探讨。下面是使用委托的一个实例:
使用委托的一个实例
//委托的使用实例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Resources;
using System.Windows.Forms;
namespace DelegateDemo
{
class DelegateDemo
{
internal delegate void FeedBack(Int32 value); //申明委托
static void Main(string[] args)
{
StaticDelegateDemo();
InstanceDelegateDemo();
ChainDelegateDemo1(new DelegateDemo());
ChainDelegateDemo2(new DelegateDemo());
}
public static void StaticDelegateDemo()
{
Console.WriteLine("--static delegate demo:--");
Counter(1,3,null);
Counter(1,3,new FeedBack(DelegateDemo.FeedBackToConsole));
Counter(1,3,new FeedBack(DelegateDemo.FeedBackToMsgBox));
Console.WriteLine();
}
private static void InstanceDelegateDemo()
{
Console.WriteLine("--Instance delegate demo--");
DelegateDemo del = new DelegateDemo();
Counter(1, 3 ,new FeedBack (del.FeedBackToFile));
Console.WriteLine();
}
public static void ChainDelegateDemo1(DelegateDemo del)
{
Console.WriteLine("--Chain delegate demo 1 --");
FeedBack fb1 = new FeedBack(FeedBackToConsole);
FeedBack fb2 = new FeedBack(FeedBackToMsgBox);
FeedBack fb3 = new FeedBack(del.FeedBackToFile);
FeedBack fbChain = null;
fbChain = (FeedBack)Delegate.Combine(fbChain, fb1);
fbChain = (FeedBack)Delegate.Combine(fbChain, fb2);
fbChain = (FeedBack)Delegate.Combine(fbChain, fb3);
Counter(1, 3, fbChain);
Console.WriteLine();
fbChain=(FeedBack)Delegate.Remove(fbChain,new FeedBack(FeedBackToMsgBox));
Counter(1,2,fbChain);
}
public static void ChainDelegateDemo2(DelegateDemo del)
{
Console.WriteLine("--Chain delegate demo 2--");
FeedBack fb1 = new FeedBack(FeedBackToConsole);
FeedBack fb2 = new FeedBack(FeedBackToMsgBox);
FeedBack fb3 = new FeedBack(del.FeedBackToFile);
FeedBack fbChain = null;
fbChain += FeedBackToConsole;
fbChain += FeedBackToMsgBox;
fbChain += del.FeedBackToFile;
Counter(1, 2,fbChain);
fbChain -= FeedBackToMsgBox;
Counter(1, 2, fbChain);
}
private static void Counter(Int32 from,Int32 to,FeedBack fb)
{
for (Int32 val = from; val <= to;val++ )
{
if (fb != null)
fb(val);
}
}
private static void FeedBackToConsole(Int32 value)
{
Console.WriteLine("Items="+value);
}
private static void FeedBackToMsgBox(Int32 value)
{
MessageBox.Show("Items"+value);
}
private void FeedBackToFile(Int32 value)
{
StreamWriter sw = new StreamWriter("status", true);
sw.WriteLine("Items" + value);
sw.Close();
}
}
}
下面我们来分析下这个实例,首先是委托的声明语句: internal delegate void FeedBack(Int32 value);
看其声明跟方法非常类似,委托类型的声明与方法签名相似, 有一个返回值和任意数目任意类型的参数。然而,实际上编译器会像下面这样定义一个完整的类:
internal class FeedBack:System.multicastDelegate
{ //构造方法 public FeedBack(); public virtual void Invoke(Int32 value); //允许回调的方法 public virtual IAsyncResult BeginInvoke(Int32 value,AsyncCallback callback,Object object); public virtual void EndInvoke(IAsyncResult result); }

|
字段 |
类型 |
描述 |
|
_target |
System.Object |
当委托对象封装一个静态方法时,这个字段为NULL,当委托对象封装一个实例时,这个字段应用的是回调方法要操作的对象。 |
|
_methodPtr |
System.IntPtr |
一个内部的整数值,CLR用它标识要回调的方法 |
|
_invocationList |
System.Object |
构造委托链时使用,通常为NULL |
每个委托对象实际上封装了一个方法和调用该方法时要操作的一个对象,如果我们写出下面两行代码:
FeedBack fb1 = new FeedBack(DelegateDemo.FeedBackToConsole);
FeedBack fb2 = new FeedBack(new DelegateDemo().FeedBackToFile);
fb1,fb2会引用两个相对独立的,已经被初始化的FeedBack 委托对象,如下图所示:

到目前为止,我们了解了委托对象的构造原理,及其内部结构,接下来我们来了解回调方法是如何调用的。
我们先引用前面代码中Counter方法的实现代码:
private static void Counter(Int32 from,Int32 to,FeedBack fb)
{
for (Int32 val = from; val <= to;val++ )
{
if (fb != null)
fb(val);
}
}
这段代码表面上像是调用了一个名叫fb的函数,然后向它传递一个参数(val),其实,编译器知道fb是一
个引用委托对象的实例,所以会生成代码调用该委托对象的invoke方法。即会将fb(val)解析成fb.Invoke(val),
换而言之,我们将源码中的fb(val)改成fb.Invoke(val),生成的IL应该是一样的,事实上也确实是这样。
参考《clr via c#》
posted @ 2011-01-13 21:00 五行缺火 阅读(297) 评论(0) 编辑


