繁体   English   中英

.NET代表:他们是如何构建的?

[英]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) targetT (args) target结构在C#中是否有效? 我没有设法用它来编译,例如:

int()target = MyMethod;

是无效的,所以用MyMetod做任何事情,例如在它上面调用.ToString() (这确实有一定意义,因为从技术上来说这是一个方法 ,但我想应该可以通过强制显式选择一个方法,例如(int())MyFunction 。所有这些都是纯粹的编译魔术吗?通过反射器查看构造揭示了另一种语法:

Func CS $ 1 $ 0000 = new Func(null,(IntPtr)Foo);

这与反汇编的构造函数签名一致,但这不能编译!

最后一个有趣的注意事项是, DelegateMulticastDelegate类还有另一组构造函数:

.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM