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

时间:2010-03-14 20:57:56

标签: c# .net delegates clr .net-internals

在检查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构造在C#中是否有效?我没有设法用它来编译,例如:

  

int()target = MyMethod;

无效,因此使用MyMetod执行任何操作,例如在它上面调用.ToString()(这确实是有道理的,因为从技术上来说这是一个方法 group ,但我想应该可以通过强制显式选择一个方法,例如{{所有这些纯粹的编译魔术都是如此?通过反射器观察结构揭示了另一种语法:

  

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

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

最后一个有趣的注意事项是,类(int())MyFunctionDelegate还有另外一组构造函数:

  

.method family hidebysig specialname rtspecialname实例        void .ctor(类System.Type目标,字符串'method')cil managed

从实例和方法指针到类型和字符串方法名称的转换在哪里?这可以通过自定义委托构造函数签名中的MulticastDelegate关键字来解释,即运行时是否在此处执行此操作?

编辑:好的,所以我想我应该重新阐述我想通过这个问题说的话。基本上我建议在委托构造中不仅涉及C#编译器/ CLR魔术,而且还有一些 Visual Studio 魔法,因为Intellisense在建议构造函数参数时会翻转一些新语法甚至隐藏其中一个它们(例如,Reflector不使用这种语法和construtor)。

我想知道这个断言是否属实,以及函数实例语法在C#中是否具有更深层含义,或者它是否只是为了清晰起见而由Visual Studio魔术部分实现的一些常量格式(这是有道理的,因为它看起来像无效C#) ?简而言之,如果我正在实施智能感知,我应该为代表做一些魔术,还是可以通过一些聪明的机制来构建建议?

最终编辑:所以,流行的共识是,这确实是VS魔术。看到这种VS行为的其他例子(参见Marc Gravell的评论)使我确信情况就是这样。

3 个答案:

答案 0 :(得分:12)

第一个参数是从对象引用中解析的(或null用于静态方法);没有魔法。

重新第二个参数 - 它是一个非托管指针(native int);简而言之,没有替代直接 C#语法可以使用此构造函数 - 它使用特定的IL指令(ldftn)来从元数据中解析函数。但是,您可以使用Delegate.CreateDelegate通过反射创建委托。你也可以使用IL发射(DynamicMethod等),但这并不好玩。

答案 1 :(得分:0)

首先定义委托(这是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#编译器提供语法糖来抽象实现细节。

答案 2 :(得分:0)

这只是猜测,所以如果我错了就不要开枪,但我认为Intellisense从委托中定义的Invoke方法获取目标方法的签名。反射器清楚地显示Invoke上的System.Action<T>方法是:

[MethodImpl(0, MethodCodeType=MethodCodeType.Runtime)]
public virtual void Invoke(T obj);

与Intellisense提供的签名建议相同。当发现一个委托类型时,魔术就是智能感知,它会查看Invoke方法,并建议一个构造函数来获取与之匹配的目标。