委托是函数指针功能在C#中的实现。
委托包装了方法,我们在C#中使用委托来间接调用方法。委托是调用该方法时要操作的对象的包装器。
委托是一种类,继承自MulticastDelegate类。它最重要的三个字段分别是:
字段 | 类型 | 作用 |
_Target | System.Object | 改字段为表明委托所在的类或实例对象。 若委托包装静态方法时:此处为null。 若委托包装实例方法时,此处为回调方法操作的对象。 |
_MethodPtr | System.IntPtr | 包装的函数的句柄,运行时用该字段来标示回调的方法 |
_invocationLIst | System.Object | 没有链接时为null 当多个委托链接在一起时,它引用一个委托数组(delegate[]) |
我们每次创建一个委托的实例时,会分析是哪个类对象的哪个方法,然后将对象传入_Target参数,方法的引用传给_MethodPtr。这样就标示了方法。
创建委托类型时,必须注意,委托与其包装的函数的返回值类型,形参列表必须一致,否则会报错。
例子:
我们使用一个Game类,然后在里面进行一些方法设置
class Game
{
public int Shout(string gamename)
{
Console.WriteLine(gamename + "真好玩~");
return 111;
}
public int Beat(string gamename)
{
Console.WriteLine(gamename + "通关了!");
return 222;
}
}
然后我们在Main函数中这样写
public delegate int GameDelegate(string a);
class Program
{
static void Main(string[] args)
{
Game game = new Game();
GameDelegate gameDelegate = new GameDelegate(game.Shout);
gameDelegate += game.Beat;
gameDelegate.Invoke("只狼");
}
}
这样就可以实现委托了,我们这里直接使用多播委托,这样的话里面包装的函数依次会被调用,看看效果:
对,我只狼确实通关了。但是如果我们如果要使用返回值呢,在代码中这样写:
int a = gameDelegate.Invoke("只狼");
Console.WriteLine("委托里的值是" + a);
输出:
输出的是委托链中最后一个方法的返回值,因为委托中每次给出返回值,下一次的就把上次的给覆盖了。
我们可以遍历委托链来得到我们想要的结果,根据MulticastDelegate类中的定义,每个委托都有GetInvocationList()方法来得到委托链的那个Object[]数组。
foreach(GameDelegate i in gameDelegate.GetInvocationList())
{
Console.WriteLine("委托里的值是" + i.Invoke("只狼"));
}
然后我们输出:
这样多播委托就实现了,不过大部分多播委托的包装函数的返回值都会设置成void,这就见仁见智了。