为什么“委托”构造函数需要两个参数?

时间:2018-07-20 06:40:41

标签: c# delegates

Delegate(Object,String)
委托(类型,字符串)

Delegate构造函数具有两个参数,第一个保存方法所属的对象的引用/类型,第二个保存指向方法的指针。

当我们直接拥有方法的地址时,为什么需要引用/对象类型?有什么用?

2 个答案:

答案 0 :(得分:2)

我只能对此进行推测。如您所说,参数是用来指定目标(类型或实例)和方法名称的。 .NET 4.7.2上的源代码是这样的:

enter image description here

此构造函数实际上无非是初始化委托实例。它未使用:

enter image description here

代表是编译器生成的类型。我不知道使用IL自定义委托的程度。看起来这些构造函数是针对根本不需要的高级场景的,或者是完全违反责任原则的。委托类与接受方法名称和对类型进行反射无关。有较干净的现有API,用于通过反射创建委托。无需使用IL编写自定义派生类型。

.NET框架从早期开始就有一些过时的东西。总而言之,.NET Framework的简洁程度令我惊讶。在这里找到一些设计错误,并且没有不好的代码基础的迹象。

答案 1 :(得分:0)

  

Delegate构造函数具有两个参数,第一个保存方法所属的对象的引用/类型,第二个保存方法的指针。

请更好地看一下签名:第二个参数是string。基本想法可能是这两个构造函数的工作方式与Type.GetMethod(string)类似,因此请在给定名称的类型内找到一个方法,但在此之上,构造函数会将其绑定到新创建的委托。请注意,该构造函数是protected,因此您需要派生的Delegate类型来调用此构造函数,并且可以从派生的委托类型中推定该方法的参数类型。

所以

public delegate void MyDelegate(int n);

然后您便可以:

var obj = new List<int>();

// an instance void Add(int) method is searched in the obj.GetType() type
// and bound to the del delegate
MyDelegate del = new MyDelegate(obj, "Add");
del(1); // obj.Add(1);

此功能尚未实现。您可以使用:

MyDelegate del = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate), obj, "Add", true);
del(1); // obj.Add(1);

但是CreateDelegate()不使用您询问的构造函数。

关于委托和方法的(本机)指针:实际上,当您创建引用方法的新委托(技术上是“方法组”)时,将使用该方法的本机指针。可以在以下example on sharplab中看到:

public delegate void TestDelegate();

public TestDelegate BuildInstanceMethodDelegate()
{
    TestDelegate test = InstanceMethod;
    return test;
}

public TestDelegate BuildStaticMethodDelegate()
{
    TestDelegate test = StaticMethod;
    return test;
}

用IL代码转换为:

.class public auto ansi sealed TestDelegate
    extends [mscorlib]System.MulticastDelegate
{
    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor (
            object 'object',
            native int 'method'
        ) runtime managed 
    {
    } // end of method TestDelegate::.ctor
}

.method public hidebysig 
    instance class TestDelegate BuildInstanceMethodDelegate () cil managed 
{
    // Method begins at RVA 0x2052
    // Code size 13 (0xd)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: ldftn instance void C::InstanceMethod()
    IL_0007: newobj instance void TestDelegate::.ctor(object, native int)

.method public hidebysig 
    instance class TestDelegate BuildStaticMethodDelegate () cil managed 
{
    // Method begins at RVA 0x2060
    // Code size 13 (0xd)
    .maxstack 8

    IL_0000: ldnull
    IL_0001: ldftn void C::StaticMethod()
    IL_0007: newobj instance void TestDelegate::.ctor(object, native int)

TestDelegate::.ctor(object, native int)的调用非常清楚,我们可以看到ldftn IL指令,该指令将非托管指针(类型native int)推向实现特定方法的本地代码。评估堆栈。。我们甚至可以在ldftn之前查看指令:如果委托是实例方法,则可以作为参考;如果委托静态方法,则可以是ldnull