Heim  >  Artikel  >  Backend-Entwicklung  >  Analysieren Sie die Unterschiede und Verbindungen zwischen Delegaten, Ereignissen, Funktionen, Aktionen und Prädikaten in C# über IL

Analysieren Sie die Unterschiede und Verbindungen zwischen Delegaten, Ereignissen, Funktionen, Aktionen und Prädikaten in C# über IL

黄舟
黄舟Original
2017-02-17 11:02:141479Durchsuche

Ich war immer verwirrt über Ereignisse und Delegationen und bin nicht sehr gut darin, sie zu nutzen. Nachdem ich mir etwas Zeit genommen habe, es zusammenzufassen, fühle ich mich viel klarer.

Lassen Sie mich zunächst über mein persönliches Verständnis sprechen:

Delegate ist ein Typ in C#, der ist eigentlich eine Klasse, die einen Verweis auf eine Methode enthalten kann.

Es gibt keinen wesentlichen Unterschied zwischen vom Delegaten deklarierten Variablen und vom Delegaten deklarierten Ereignissen. Ereignisse werden auf der Grundlage der vom Delegaten deklarierten Variablen gepackt, ähnlich wie bei der Beziehung zwischen Variablen und Attributen (Sie können im IL-Code sehen, dass jedes von einem Delegaten deklarierte Ereignis einer von einem privaten Delegaten deklarierten Variablen entspricht) verbessert die Sicherheit.

Aktion und Funktion: Diese beiden sind eigentlich die vom System definierten Delegaten. Es gibt viele überladene Methoden, um verschiedene Anwendungssituationen zu erleichtern. Es befindet sich im System-Namensraum des Systems und ist daher global sichtbar.

Lassen Sie uns zunächst die Bedeutung der Symbole in ILDasm verstehen:

Dieses Bild stammt von: http://www.php.cn/

Schritte zur Delegationserstellung:

1. Verwenden Sie das Schlüsselwort „Delegate“, um einen Delegaten zu erstellen, einschließlich der Deklaration des Rückgabewerts und des Parametertyps.
2. Empfangen Sie den Delegaten, wo er verwendet wird Parametertyp und übergeben Sie ihn dort


1. Ereignisse und Delegationen



Erstellen Sie ein neues Event-Delegationstestprojekt: EventDelegateTest

Der spezifische Code lautet wie folgt:

<span style="font-size:14px;"><span style="font-size:14px;">namespace EventDelegateTest
{
    public class TestClass
    {
        public delegate int delegateAction();
        public event delegateAction OnActionEvent;
        public delegateAction daNew;
    }
}</span></span>

Verwenden Sie nach dem Kompilieren des Codes die mitgelieferte ILDASM.EXE mit Visual Studio 2010:



Öffnen Sie die DLL und Sie können siehe folgende Informationen:



Von oben Im Bild können wir die folgenden Informationen sehen:

1. Delegation öffentlicher Delegat int DelegateAction();

existiert in Form einer Klasse ( DelegateAction) in IL

.NET definiert einen Delegaten als versiegelte Klasse, abgeleitet von der Basisklasse System.MulticastDelegate, und erbt die drei Methoden der Basisklasse


2. öffentliches Ereignis DelegateAction OnActionEvent;

In IL entspricht es nicht nur zum Ereignis OnActionEvent, entspricht aber auch einem Feld OnActionEvent;

Das vom Feld OnActionEvent und dem öffentlichen DelegatAction daNew generierte Feld daNew ist dasselbe





都是以字段(field )的形式存在的。

双击event OnActionEvent可以看到如下信息:




在IL中事件被封装成了包含一个add_前缀和一个remove_前缀的的代码段。

其中,add_前缀的方法其实是通过调用Delegate.Combine()方法来实现的,组成了一个多播委托;remove_就是调用Delegate.Remove()方法,用于移除多播委托中的某个委托。

也就是说:事件其实就是一个特殊的多播委托

那么对于事件进行这一次封装有什么好处呢?

1、因为delegate可以支持的操作非常多,比如我们可以写onXXXChanged += aaaFunc,把某个函数指针挂载到这个委托上面,但是我们也可以简单粗暴地直接写onXXXChanged = aaaFunc,让这个委托只包含这一个函数指针。不过这样一来会产生一个安全问题:如果我们用onXXXChanged = aaaFunc这样的写法,那么会把这个委托已拥有的其他函数指针给覆盖掉,这大概不是定义onXXXChanged的程序员想要看到的结果。

小注:

    虽然事件不能直接=某个函数,也不可以直接=null


2、还有一个问题就是onXXXChanged这个委托应该什么时候触发(即调用它所包含的函数指针)。从面向对象的角度来说,XXX改变了这个事实(即onXXXChaned的字面含义)应该由包含它的那个对象来决定。但实际上我们可以从这个对象的外部环境调用onXXXChanged,这既产生了安全问题也不符合面向对象的初衷。 

说到这里对于事件与委托的管理算是说明白了,那么平时常用的Action与Func,与委托又有什么关系呢?


二、Action 与Func


Action 委托:封装一个方法,该方法具有参数(0到16个参数)并且不返回值。

具体形式如下:http://www.php.cn/(v=vs.110).aspx


Func71fba9c8d5bcb8609eb4c5c1a9528abd 委托:封装一个具有参数(0到16个参数)并返回 TResult 参数指定的类型值的方法。

具体形式如下:http://www.php.cn/(v=vs.110).aspx


那么这Action与Func是怎么实现的呢?

1、Action(以Action5d766edf0ee4a0fde742e7cd6e836235 委托:封装一个方法,该方法具有两个参数并且不返回值为例)

从微软公布的源码中,可以看到,如下实现:


public Action<bool,bool>  ac;

上面这个声明就是:该方法具有两个参数并且不返回值的委托。


其余使用方式与委托变量一样。

2、Func(以Funcb558850b559c1225634175ee86be5f85 委托:封装一个具有两个参数并返回 TResult 参数指定的类型值的方法为例)
从微软公布的源码中,可以看到,如下实现:



此处,可以看出Func与Action是类似的,唯一的区别就是,Func必须指定返回值的类型,使用方式与委托咱们自己使用委托变量是一样的,直接使用相应参数的Func或者Action声明变量,=或者+=挂载函数(方法即可)

这两个其实说白了就是系统定义好的Delegate,他有很多重载的方法,便于各种应用情况下的调用。他在系统的System命名空间下,因此全局可见。


三、Predicate


是返回bool型的泛型委托,Predicate有且只有一个参数,返回值固定为bool。表示定义一组条件并确定指定对象是否符合这些条件的方法。此方法常在集合(Array 和 List8742468051c85b06f0a0af9e3e506b5c)的查找中被用到,如:数组,正则拼配的结果集中被用到。

官方文档:点击打开链接


具体用法demo如下:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace IconTest
{
    public partial class Form2 : Form
    {
        Predicate<int> myPredicate;
        int[] myNum = new int[8] { 12, 33, 89, 21, 15, 29, 40, 52 };
        public int[] myResult;
        public Form2()
        {
            InitializeComponent();
            myPredicate = delegate(int curNum)             
            {
                if (curNum % 2 == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            };
        }
        private void Form2_Load(object sender, EventArgs e)
        {
            myResult = Array.FindAll(myNum, myPredicate);
        }          
    }
}

上例中说明了Predicate的使用,FindAll方法中,参数2即是一个Predicate,在具体的执行中,每一个数组的元素都会执行指定的方法,如果满足要求返回true,并会被存放在结果集中,不符合的则被剔除,最终返回的集合,即是结果判断后想要的集合。
Array.FindAll 泛型方法:点击打开链接


以上代码执行结果为:


那么Predicate8742468051c85b06f0a0af9e3e506b5c与委托又有什么关系呢?


从微软源码中可以看出Predicate8742468051c85b06f0a0af9e3e506b5c是返回bool型的泛型委托,从本质上来说与Func、Action、事件、委托变量并无本质区别。




 以上就是通过IL分析C#中的委托、事件、Func、Action、Predicate之间的区别与联系的内容,更多相关内容请关注PHP中文网(www.php.cn)!



Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn