扩展方法可以被分配到匹配的对象上它们的用法,这样的代表:
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)”上的值类型“INT”定义不能用于创建代表。
他们为什么不能?
在回答我的其他回答,埃里克·史密斯正确地指出:
“......因为它需要隐式拳击接收器类型参数...”。 这无论如何是会发生什么,如果你做这样的事情:函数F = 5.ToString; 这是完全合法的。
想到这里使我一个新的答案。 试试这个关于大小:
上结构普通“实例”的方法采取,在CIL水平,“托管指针”(类型&
),为接收器的参数。 这是必要的,这样的结构实例方法可以分配给结构的领域。 见分区Ⅱ,第13.3节 。
类似地,在类实例方法采取“对象引用”(类型O
),为接收器参数(不同之处在于这是一个指向托管堆,并且需要被跟踪为GC)。
由于两个CIL &
S和O
可以均为(并)通过指针来实现,一切都是没说的委托执行。 无论委托是否捕捉静态方法,一个类的实例方法,或结构实例方法,它需要做的一切就是指向其传递_target
给函数的第一个参数。
但情况下,我们正在讨论的是一片废墟。 静态扩展方法服用int
作为第一参数需要类型的CIL参数int32
(请参阅分区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
方法,反射器是没有太大的帮助。 该用于createDelegate方法文档也并没有太大的帮助。 我敢肯定,它有事情做与拳击的接收器,可能与转子源的知识,有人可以帮助解释为什么?
文章来源: Extension methods defined on value types cannot be used to create delegates - Why not?