C#中委托(delegate)和多播委托的理解

委托

委托是寻址方法的.NET版本。

在C#高级编程(第七版)中这是对委托的第一句描述。

什么是寻址方法?
简单理解为我们通过委托传递一个方法给另一个方法。

什么时候需要传递方法?
在微软的官方文档和C#高级编程(第七版)这本书都提到一个例子-----在对象的排序算法中,需要对对象进行比较,而不同对象比较的方法不同,所以比较两个对象的方法的引用可以作为参数传递到排序算法中,这个时候就需要传递方法。

通过什么传递方法?

在理解委托的时候经常将其与C++中的函数指针做比较,函数指针只是一个指向内存位置的指针,它不是类型安全的,我们无法判断这个指针实际指向什么,参数和返回类型更加无从知晓。但我们可以通过该函数指针获得该方法也可以理解为通过传递地址来传递该方法
函数指针是面向过程的,而C#是面向对象编程,几乎没有方法是孤立存在的,而是在调用方法之前需要与类的实例相关联。
所以.NET框架不允许使用函数指针这种直接的方法,因为这这很不面向对象!
那如何才符合面向对象的核心价值观?—————— 委托
在C#中要传递方法,就必须把方法的细节封装在一种新类型的对象中,即委托。委托只是一种特殊类型的对象,其特殊之处在于,我们定义的所有对象都包含数据,而委托包含的只是一个或多个方法的地址。

总结

委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。 在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。 你可以通过委托实例调用方法。
委托用于将方法作为参数传递给其他方法。
这符合.NET规范,对比函数指针 ,委托 是面向对象的、类型安全的和可靠的,但也损失了灵活性!


委托的使用:

声明一个委托:

public delegate int operation(int num1, int num2);

该委托表示的方法有俩个int类型的参数,返回值也为int类型。
要注意的是其语法类似于方法的定义,但没有方法体,关键字为delegate
定义委托相当于定义一个新类(其实还真是定义一个类),所有定义的位置可以是在定义类的任何相同的地方,可以在类的内部或者外部定义。

可以实例该委托的方法(即方法的参数和返回值和委托一致):
也可以说是可以被该委托封装的方法

       // Create  methods for a delegate.
       public int add(int num1,int num2) 
        {
            return num1 + num2;
        }
        public int reduce(int num1, int num2)
        {
            return num1 - num2;
        }

实例委托:
在官方文档和高级编程书中可以看到两种实例方法:

operation someoperation = new operation(reduce);//法一:通过在委托的构造函数中添加委托引用的方法
//operation someoperation = add;//法二:直接让委托对象等于引用的方法

调用委托:

       someoperation (num1,num2);

注意:
因为委托的实例为一个对象所有,可以作为一个方法的参数:

      public int numMethod(int num1, int num2, operation callback)
        {
            return callback(num1,num2);
        }

并且我们可以将委托的实例传入该方法,也可以直接将方法传入

            operation someoperation = new operation(reduce);
            int result = numMethod(2, 1, someoperation);//法一:传入委托实例
            //int result = numMethod(2, 1, reduce);//法二:直接传入方法

多播委托

委托可以调用多个方法。 这被称为多播。 若要向委托的方法列表(调用列表)添加其他方法,只需使用加法运算符或加法赋值运算符(“+”或“+=”)添加两个委托,也可以通过(“-”或“-=”)去除委托。 例如:

MethodClass obj = new MethodClass();
Del d1 = obj.Method1;
Del d2 = obj.Method2;
Del d3 = obj.Method3;

//添加多个委托
Del allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;
------------------------------------------
//去除委托的方法
allMethodsDelegate -= d1;

// copy AllMethodsDelegate while removing d2
Del oneMethodDelegate = allMethodsDelegate - d2;

注意3个方法都是该委托可以封装的方法,且多播委托封装的方法返回值必须都为void,不然只能得到调用最后一个方法的结果。

最后:
多播委托广泛用于事件处理中。 事件源对象将事件通知发送到已注册接收该事件的接收方对象。 若要注册一个事件,接收方需要创建用于处理该事件的方法,然后为该方法创建委托并将委托传递到事件源。 事件发生时,源调用委托。 然后,委托将对接收方调用事件处理方法,从而提供事件数据。 给定事件的委托类型由事件源确定。

更多进阶的内容

Action和Func泛型委托,委托,泛型,匿名函数,Lambda表达式的综合使用
事件(event)和委托(delegate)的综合运用实例(WinForm控件事件执行流程和原理),和EventHandler委托

你可能感兴趣的:(C#,委托,多播委托)