c# 委托

概述

委托是一个类,它定义了方法的类型,使得可以将方法作为另一个方法的参数进行传递。

委托是一个引用类型,具有引用类型所有的特性,它保存的不是实际值,而是一个存储在托管堆(managed heap)上的对象引用,也就是一个方法(函数)的引用。

C#委托类似C++中的函数指针,所不同的是委托是类型安全的,委托会检测它所保存的函数引用是否写声明的委拖匹配,而函数指针只保存一个内存地址,不附带参数类型、参数个数、返回值等任何额外信息。

当我们用delegate关键字声明委托时,编译器自动为我们生成类,该类继承自[mscorlib]System.MulticastDelegate,类的名字即为委托变量名,访问类型为定义的委托访问类型(如:public)。

在使用委托的时候,你可以像对待一个类一样对待它。即先声明,再实例化。只是有点不同,类在实例化之后叫对象或实例,但委托在实例化后仍叫委托。

 

委托类结构

 

示例:

using System;

namespace 委托本质
{
    class Program
    {
        public delegate void TestDelegate(int i); //定义委托


        static void Main(string[] args)
        {
            //调用委托方法
            TestDelegate myDelgate = new TestDelegate(PrintMessage1);
            myDelgate (0);  //等价于: myDelegate.Invoke(0); 
            myDelgate (1);            
            Console.Read();
        }

        /// <summary>
        /// 一个静态方法,符合TestDelegate的定义
        /// </summary>
        /// <param name="i">整型参数</param>
        static void PrintMessage1(int i)
        {
            Console.WriteLine("" + i + "个方法");
        }
    }
}

委托的内部结构

_methodPtr:指向委托对应的方法引用;

_target:指向方法所在对象引用,如果为静态方法,其值为“null”;

对于继承自System.MuticastDelegate类的自定义委托来说,还有_prev属性,用来维护一个链式委托,详见委托链介绍。

委托链(链式委托)

委托链不是一个新概念,它的实质就是由委托组成的链表,我们自定义的委托均继承自System.MulticastDelegate,所有自定义的委托都是一个委托链表;

代码示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace myspace
{
    class Program
    {
        /// <summary>
        /// 定义的委托。
        /// </summary>
        public delegate void TestMultiDelegate();
static void Main(string[] args) { //申明一个委托变量,并绑定第一个方法 TestMultiDelegate handler = new TestMultiDelegate(PrintMessage1); //绑定第二个方法 handler += new TestMultiDelegate(PrintMessage2); //绑定第三个方法 handler += new TestMultiDelegate(PrintMessage3);
//检查结果 handler();  //依次调用了方法1~3 Console.Read(); } static void PrintMessage1() { Console.WriteLine("第一个方法"); } static void PrintMessage2() { Console.WriteLine("第二个方法"); } static void PrintMessage3() { Console.WriteLine("第三个方法"); } } }

上面代码一个等价的写法:

TestMultiDelegate handler = new TestMultiDelegate(PrintMessage1);           
TestMultiDelegate handler2 = new TestMultiDelegate(PrintMessage2);
TestMultiDelegate handler3 = new TestMultiDelegate(PrintMessage3);
TestMultiDelegate handlerhead = handler + handler2 + handler3;
handlerhead.Invoke();   //或执行:handler()/handler.Invoke();

事实上,上面这段代码没有为handlerhead分配任何委托实例,而仅仅把所有委托串联,并让handlerhead引用到委托链的头上,所以handlerhead和handler实际上引用了同一个委托实例,执行handlerhead.Invoke() 与 handler.Invoke()返回结果也就一模一样了。

补充说明

链式委托的执行顺序是按照委托链上的顺序从当前委托开始依次往后执行,必要时可以使用GetInvocationList()方法来获得委托链上所有需要执行的委托,并且按照任何希望的顺序去执行(Invoke)它们。

委托可以是带有返回值的方法,但多个带返回值的方法被添加到委托链中时,程序员需要手动地调用委托链上的每个方法得到其返回值,否则只能返回委托链上最后一个被执行方法的返回值。

委托的应用场合通常是任务的执行者把细节工作进行再分配,执行者确切地知道什么工作将要被执行,把执行细节委托给其他组件、方法或者程序集完成。

参考

百度百科 http://baike.baidu.com/item/%E5%A7%94%E6%89%98/7900553#viewPageContent

浅谈.net中的委托 http://www.cnblogs.com/DebugLZQ/archive/2012/08/23/2649813.html

C#中的委托和事件 http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx

原文地址:https://www.cnblogs.com/ybtools/p/6722767.html