[英]Delegates in .NET: how are they constructed?
在检查C#和.NET中的代表时,我注意到一些有趣的事实:
在C#中创建委托使用构造函数创建从MulticastDelegate
派生的类:
.method public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed { }
这意味着它需要实例和指向该方法的指针。 然而,在C#中构造委托的语法表明它有一个构造函数
new MyDelegate(int () target)
我可以将int ()
识别为函数实例( int *target()
将是C ++中的函数指针)。 很明显,C#编译器从函数名定义的方法组中选出正确的方法并构造委托。 所以第一个问题是,C#编译器(或者Visual Studio,准确地说)从哪里选择这个构造函数签名? 我没有注意到任何可以区分的特殊属性或东西。 这是某种编译器/ visualstudio魔术吗? 如果没有, T (args) target
# T (args) target
结构在C#中是否有效? 我没有设法用它来编译,例如:
int()target = MyMethod;
是无效的,所以用MyMetod
做任何事情,例如在它上面调用.ToString()
(这确实有一定意义,因为从技术上来说这是一个方法组 ,但我想应该可以通过强制显式选择一个方法,例如(int())MyFunction
。所有这些都是纯粹的编译魔术吗?通过反射器查看构造揭示了另一种语法:
Func CS $ 1 $ 0000 = new Func(null,(IntPtr)Foo);
这与反汇编的构造函数签名一致,但这不能编译!
最后一个有趣的注意事项是, Delegate
和MulticastDelegate
类还有另一组构造函数:
.method family hidebysig specialname rtspecialname instance void .ctor(类System.Type target,string'method')cil managed
从实例和方法指针到类型和字符串方法名称的转换在哪里发生? 这可以通过自定义委托构造函数签名中的runtime managed
关键字来解释,即运行时是否在此处执行此操作?
编辑 :好的,所以我想我应该重新阐述我想通过这个问题说的话。 基本上我建议不仅C#编译器/ CLR魔术涉及委托构造,而且还有一些Visual Studio魔术,因为Intellisense在建议构造函数参数时会翻转一些新语法甚至隐藏其中一个(例如Reflector不使用)这个语法和construtor,就此而言)。
我想知道这个断言是否属实,以及函数实例语法在C#中是否具有更深层的含义,或者它只是为了清晰起见而由Visual Studio魔术部分实现的一些常量格式(这是有道理的,因为它看起来像无效的C#)? 简而言之,如果我正在实施Intellisense,我应该为代表做一些魔术还是我可以通过一些聪明的机制构建建议?
最终编辑 :所以,流行的共识是,这确实是VS魔术。 看到这种VS行为的其他例子(参见Marc Gravell的评论)使我确信这是事实。
第一个参数是从对象引用解析的(或静态方法为null
); 没有魔法。
但是, 第二个参数是 - 它是一个非托管指针(native int); 简而言之,没有可以使用此构造函数的替代直接 C#语法 - 它使用特定的IL指令( ldftn
)从元数据中解析函数。 但是,您可以使用Delegate.CreateDelegate
通过反射创建委托。 你也可以使用IL emit( DynamicMethod
等),但它并不好玩。
首先定义委托(这是Visual Studio知道目标方法的签名的方式):
delegate void MyDelegate();
然后你像这样构造委托实例:
MyDelegate method = new MyDelegate({method name});
// If this was the method you wanted to invoke:
void MethodToInvoke()
{
// do something
}
MyDelegate method = new MyDelegate(MethodToInvoke);
C#自动选择与委托签名匹配的方法。
编辑:当Visual Studio的Intellisense向您显示int () target
建议时,它会显示您可以使用的C#方法的签名。 C#编译器将C#表示转换为IL。 IL实现看起来会有所不同,因为IL不是C风格的语言,C#编译器提供语法糖来抽象实现细节。
这只是一个猜测,所以如果我错了就不要开枪,但我认为Intellisense从委托中定义的Invoke
方法获得目标方法的签名。 Reflector清楚地表明System.Action<T>
上的Invoke
方法是:
[MethodImpl(0, MethodCodeType=MethodCodeType.Runtime)]
public virtual void Invoke(T obj);
这与Intellisense提供的签名建议相同。 当发现委托类型时,神奇的是Intellisense,查看Invoke
方法并建议一个构造函数,它接受与之匹配的目标。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.