在值类型上定义的扩展方法不能用于创建委托 - 为什么不? [英] Extension methods defined on value types cannot be used to create delegates - Why not?

查看:197
本文介绍了在值类型上定义的扩展方法不能用于创建委托 - 为什么不?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

扩展方法可以分配给与对象的使用相匹配的代理,如下所示:

Extension methods can be assigned to delegates that match their usage on an object, like this:

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"

如果他们要扩展的类型是值类型,工作:

If the type they're extending is a value type, it won't work:

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'不能用于创建委托。

Error CS1113: Extension methods 'FunnyExtension.Double(int)' defined on value type 'int' cannot be used to create delegates.

为什么不能?

推荐答案

为了回应我的其他答案,Eric Smith正确的注释:

In response to my other answer, Eric Smith correctly notes:


...因为它需要隐式地包装接收器类型参数...。无论如何,如果你做了这样的事情:Func f = 5.ToString;这是完全合法的。

"... because it would require implicitly boxing the receiver type parameter ...". Which is what happens anyway, if you do something like this: Func f = 5.ToString; Which is perfectly legal.

想到这一点导致我得到一个新的答案。尝试这样大小:

Thinking about this has led me to a new answer. Try this on for size:

结构上的普通实例方法在CIL级别采用管理指针(类型& )作为接收器参数。这是必要的,因此结构体上的实例方法可以分配给结构体的字段。请参阅分区II ,第13.3节

Ordinary "instance" methods on structs take, at the CIL level, a "managed pointer" (type &) as a receiver parameter. This is necessary so that instance methods on structs can assign to fields of the struct. See Partition II, Section 13.3.

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

Similarly, instance methods on classes take an "object reference" (type O) as a receiver parameter (the difference being that this is a pointer to the managed heap, and needs to be tracked for GC).

既然CIL <$ c可以通过指针实现$ c>& s和 o 可以为代理实现提供一切平衡。无论代理是捕获静态方法,类实例方法还是结构体实例方法,都需要做的是将指针传递给其 _target 到第一个参数的功能。

Since both CIL &s and Os can be (and are) implemented by pointers, everything is hunky-dory for the delegate implementation. Regardless of whether a delegate captures a static method, a class instance method, or a struct instance method, all it needs to do is pass the pointer to its _target to the first argument of the function.

但是我们正在讨论的场景是废墟。使用 int 作为第一个参数的静态扩展方法需要一个类型为 int32 的CIL参数(请参见分区III,部分1.1.1)。 这里是导轨的位置。我没有看到为什么不会为了实现代理而意识到这种情况(为了例如,通过检查与正在捕获的MethodInfo相关联的元数据),并发出一个thunk,它将取消收藏 _target 并将其作为第一个参数,但是 t代表对结构体的经典实例方法的需要,因为他们期望一个指针,而不会出现(根据我之前的错误答案中的例子)来实现。显然,具体的价值类型可以控制所需的thunk的确切性质。

But the scenario we are discussing ruins that. A static extension method taking an int as a first argument requires a CIL argument of type int32 (see Partition III, section 1.1.1). Here is where things go off the rails. I don't see any reason why it wouldn't be possible for the implementation of delegates to realize that this was happening (for example, by inspecting the metadata associated with the MethodInfo being captured) and emit a thunk that would unbox the _target and pass that as the first argument, but this isn't needed for delegates to classical instance methods on structs, since they expect a pointer anyway and doesn't appear (judging by the example in my earlier incorrect answer) to be implemented. Obviously the specific value type in question would control the exact nature of the required thunk.

除非我错过了一个更基本的实施障碍(我可以想象它会构成例如验证者的问题),似乎合理的情况可能会延长运行时间来支持这种情况,但是所有的迹象都指向这是运行时的限制,而不是C#编译器本身的限制。

Unless I am missing a more fundamental obstacle to implementation (I could imagine that it would pose problems for the verifier, for example), it seems like a reasonable case could be made for extending the runtime to support this case, but all the signs are pointing towards this being a limitation of the runtime and not of the C# compiler per se.

这篇关于在值类型上定义的扩展方法不能用于创建委托 - 为什么不?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆