私はイベントと委任についていつも混乱していて、それらを使用するのがあまり得意ではありません。時間をかけてまとめてみると、かなりすっきりした気分になりました。
まず、私の個人的な理解の結論について話させてください:
delegate は C# の型であり、実際にはメソッドへの参照を保持できるクラスです。
デリゲートによって宣言された変数とデリゲートによって宣言されたイベントの間に本質的な違いはありません。イベントは、変数と属性の関係と同様に、デリゲートによって宣言された変数に基づいてパッケージ化されます (IL で確認できます)。 code デリゲートによって宣言された各イベントは、デリゲートによって宣言されたプライベート変数に対応します)。これにより、セキュリティが向上します。
アクションと機能: これら 2 つは実際にはシステムによって定義されたデリゲートであり、さまざまなアプリケーション状況での呼び出しを容易にするための多くのオーバーロードされたメソッドがあります。これはシステムの System 名前空間の下にあるため、グローバルに表示されます。
まず、ILDasm のアイコンの意味を理解しましょう:
この画像の出典: http://www.php.cn/
コミッション作成手順:
1. delegate キーワードを使用して、戻り値とパラメーターの型の宣言を含むデリゲートを作成します
2. 使用されている場所でデリゲートを受け取ります
3. このデリゲートのインスタンスを作成し、戻り値と一致するメソッドを指定しますおよびそれを渡すパラメーターの型
1. イベントと委任
新しいイベント委任テストを作成しますプロジェクト: EventDelegateTest
具体的な内容コードは次のとおりです:
<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>
コードをコンパイルした後、Visual Studio 2010 に付属の ILDASM.EXE を使用します。 DLLを開いてください、あなた次の情報を確認できます:
上の図から次の情報を確認できます:
1.
それIL ではクラス (delegateAction) の形式で存在します
IL では、イベント OnActionEvent に対応するだけでなく、フィールド OnActionEvent; にも対応します
そして、フィールド OnActionEvent は、によって生成されたフィールド daNew と同じです。パブリック デリゲートアクション daNew
都是以字段(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 委托:封装一个方法,该方法具有两个参数并且不返回值为例) 从微软公布的源码中,可以看到,如下实现: 上面这个声明就是:该方法具有两个参数并且不返回值的委托。 其余使用方式与委托变量一样。 2、Func(以Funcb558850b559c1225634175ee86be5f85 委托:封装一个具有两个参数并返回 TResult 参数指定的类型值的方法为例) 此处,可以看出Func与Action是类似的,唯一的区别就是,Func必须指定返回值的类型,使用方式与委托咱们自己使用委托变量是一样的,直接使用相应参数的Func或者Action声明变量,=或者+=挂载函数(方法即可) 这两个其实说白了就是系统定义好的Delegate,他有很多重载的方法,便于各种应用情况下的调用。他在系统的System命名空间下,因此全局可见。 三、Predicate 是返回bool型的泛型委托,Predicate有且只有一个参数,返回值固定为bool。表示定义一组条件并确定指定对象是否符合这些条件的方法。此方法常在集合(Array 和 List8742468051c85b06f0a0af9e3e506b5c)的查找中被用到,如:数组,正则拼配的结果集中被用到。 官方文档:点击打开链接 具体用法demo如下: 上例中说明了Predicate的使用,FindAll方法中,参数2即是一个Predicate,在具体的执行中,每一个数组的元素都会执行指定的方法,如果满足要求返回true,并会被存放在结果集中,不符合的则被剔除,最终返回的集合,即是结果判断后想要的集合。 以上代码执行结果为: 那么Predicate8742468051c85b06f0a0af9e3e506b5c与委托又有什么关系呢? 从微软源码中可以看出Predicate8742468051c85b06f0a0af9e3e506b5c是返回bool型的泛型委托,从本质上来说与Func、Action、事件、委托变量并无本质区别。
以上就是通过IL分析C#中的委托、事件、Func、Action、Predicate之间的区别与联系的内容,更多相关内容请关注PHP中文网(www.php.cn)!public Action<bool,bool> ac;
从微软公布的源码中,可以看到,如下实现: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);
}
}
}
Array.FindAll 泛型方法:点击打开链接