可以将扩展方法分配给与对象的用法相匹配的委托,如下所示:

static class FunnyExtension {
    public static string Double(this string str) { return str + str; }
    public static int Double(this int num) { return num + num; }
}


Func<string> aaMaker = "a".Double;
Func<string, string> doubler = FunnyExtension.Double;

Console.WriteLine(aaMaker());       //Prints "aa"
Console.WriteLine(doubler("b"));    //Prints "bb"

如果他们扩展的类型是值类型,则不起作用:

Func<int> eightMaker = 4.Double;    //Error CS1113: Extension methods 'FunnyExtension.Double(int)' defined on value type 'int' cannot be used to create delegates
Func<int, int> intDoubler = FunnyExtension.Double;  //Works

这给出了

  

错误CS1113:定义了扩展方法'FunnyExtension.Double(int)'   on value type'int'不能用于创建委托。

他们为什么不能?

有帮助吗?

解决方案

回应我的另一个答案,Eric Smith正确地指出:

  

&quot; ...因为它需要隐式装箱接收器类型参数......“。无论如何会发生什么,如果你做这样的事情:Func f = 5.ToString;这是完全合法的。

考虑到这一点,我得到了一个新答案。试试这个尺寸:

普通“实例”结构上的方法在CIL级别上采用“受管指针”。 (输入&amp; )作为接收器参数。这是必要的,以便结构上的实例方法可以分配给结构的字段。请参阅分区II ,第13.3节

类似地,类上的实例方法采用“对象引用”。 (输入 O )作为接收器参数(区别在于这是指向托管堆的指针,需要跟踪GC)。

由于CIL &amp; O 都可以(并且是)通过指针实现,所以对于委托实现来说,一切都是hunky-dory。无论委托是否捕获静态方法,类实例方法或结构实例方法,它所需要做的就是将指针传递给 _target 到函数的第一个参数。

但我们正在讨论的情景破坏了这一点。以 int 作为第一个参数的静态扩展方法需要类型为 int32 的CIL参数(参见第III部分,第1.1.1节)。 这是事情发生的地方。我认为没有任何理由说明为什么可能实施代表才意识到这种情况正在发生(对于例如,通过检查与正在捕获的MethodInfo相关联的元数据)并发出一个thunk,它将取消打包 _target 并将其作为第一个参数传递,但这对于经典代理不需要结构上的实例方法,因为它们总是希望指针并且不会出现(通过我之前的错误答案中的示例来判断)。显然,有问题的特定值类型将控制所需thunk的确切性质。

除非我错过了一个更基本的实现障碍(例如,我可以想象它会给验证者带来问题),似乎可以通过扩展运行时来支持这种情况,但所有情况都是合理的。标志指向这是运行时的限制,而不是C#编译器本身的限制。

其他提示

编辑2 我不再相信这个答案了,但我把它放在这里所以线程仍然有意义,所以人们会明白为什么它不对。请参阅我的其他答案,了解对此事的不同看法。

<强>原始

因为它需要隐式装箱值类型接收器参数(因为System.Delegate类型中保存接收器参数的_target字段是System.Object类型),如果你不是这样,可能会导致一些奇怪的别名行为期待它。

修改

此处还有其他事情发生。我运行了这个示例程序:

class Program
{
    public static int Combine(int a, int b)
    {
        return a + b;
    }

    static void Main(string[] args)
    {
        var combineMethod = typeof(Program).GetMethod("Combine");
        var add4 = Delegate.CreateDelegate(
                              typeof(Converter<int, int>),
                              4,
                              combineMethod) as Converter<int, int>;

        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(add4(i));
        }
        Console.ReadLine();
    }
}

并得到一个ArgumentException:“绑定到目标方法的错误。”在调用CreateDelegate时。我不确定为什么,因为相关的方法是 internalcall 方法,Reflector没有多大帮助。 CreateDelegate 的文档也没什么帮助。我确定它与装箱接收器有关,也许知道Rotor源的人可能有助于解释原因吗?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top