.NET 中的代表:它们是如何构造的?
-
19-09-2019 - |
题
在检查 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)从哪里选择这个构造函数签名?我没有注意到任何特殊属性或会产生区别的东西。这是某种编译器/视觉工作室魔法吗?如果不是的话,是 T (args) target
构造在 C# 中有效吗?我没有设法用它来编译任何东西,例如:
int () 目标 = MyMethod;
是无效的,所以做任何事情都是无效的 MyMetod
, ,例如呼叫 .ToString()
就它而言(这确实有一定道理,因为这在技术上是一种方法 团体, ,但我想应该可以通过强制转换来显式地选择一个方法,例如 (int())MyFunction
. 。那么这一切纯粹是编译器的魔法吗?通过反射器查看构造揭示了另一种语法:
Func CS$1$0000 = new Func(null, (IntPtr) Foo);
这与反汇编的构造函数签名一致,但无法编译!
最后一个有趣的说明是,这些课程 Delegate
和 MulticastDelegate
还有另一组构造函数:
。
从实例和方法指针到类型和字符串方法名称的转换发生在哪里?这可以解释为 runtime managed
自定义委托构造函数签名中的关键字,即运行时在这里做它的工作吗?
编辑:好的,所以我想我应该通过这个问题重新表述我想说的内容。基本上我建议委托构造中不仅涉及 C# 编译器/CLR 魔法,还涉及一些 视觉工作室 神奇的是,因为智能感知在建议构造函数参数时会弹出一些新语法,甚至隐藏其中之一(例如Reflector 不使用此语法和构造函数)。
我想知道这个断言是否正确,以及函数实例语法在 C# 中是否有更深层的含义,或者只是 Visual Studio 魔术部分为了清晰起见而实现的某种常量格式(这是有道理的,因为它看起来像无效的 C#)?简而言之,如果我正在实现智能感知,我应该为代表们施展一些魔法,还是可以通过某种巧妙的机制构建建议?
最终编辑:所以,普遍的共识是,这确实是VS魔法。看到此类 VS 行为的其他示例(请参阅 Marc Gravell 的评论)让我相信情况确实如此。
解决方案
第一个参数是从对象引用解析的(或 null
对于静态方法);那里没有魔法。
重新 第二 然而,参数 - 它是一个非托管指针(本机 int);简而言之,别无选择 直接的 可以使用此构造函数的 C# 语法 - 它使用特定的 IL 指令 (ldftn
) 从元数据解析函数。但是,您可以使用 Delegate.CreateDelegate
通过反射创建委托。您还可以使用 IL 发出(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
委托上定义的方法。反射镜清楚地表明 Invoke
方法上 System.Action<T>
是:
[MethodImpl(0, MethodCodeType=MethodCodeType.Runtime)]
public virtual void Invoke(T obj);
这与Intellisense提供的签名建议相同。神奇的是智能感知,当发现委托类型时,会查看 Invoke
方法并建议一个采用与其匹配的目标的构造函数。