两个 C# 扩展泛型方法之间的不明确调用,其中一个 where T:class 和另一个 where T:struct
考虑两个扩展方法:
public static T MyExtension<T>(this T o) where T:class
public static T MyExtension<T>(this T o) where T:struct
和一个类:
class MyClass() { ... }
现在在上述类的实例上调用扩展方法:
var o = new MyClass(...);
o.MyExtension(); //compiler error here..
o.MyExtension<MyClass>(); //tried this as well - still compiler error..
当我在类上调用该方法时,编译器表示调用该方法是一个不明确的调用。我本以为它可以确定要调用哪个扩展方法,因为 MyClass 是一个类,而不是一个结构?
Consider two extension methods:
public static T MyExtension<T>(this T o) where T:class
public static T MyExtension<T>(this T o) where T:struct
And a class:
class MyClass() { ... }
Now call the extension method on a instance of the above class:
var o = new MyClass(...);
o.MyExtension(); //compiler error here..
o.MyExtension<MyClass>(); //tried this as well - still compiler error..
The compiler says that calling the method is an ambiguous call when I call it on a class. I would have thought that it could determine which extension method to call, as MyClass is a class, not a struct?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
编辑:我现在已经写了关于此的博客更详细地说。
我最初的(现在我认为不正确)想法:在重载解析和类型推断阶段不考虑通用约束 - 它们仅用于验证重载解析的结果。
编辑:好的,经过长时间的讨论后,我想我已经到了。基本上我的第一个想法几乎是正确的。
泛型类型约束仅在非常有限的情况下从候选集中删除方法......特别是仅当参数本身的类型是泛型时;不仅仅是类型参数,而且是使用泛型类型参数的泛型类型。此时,验证的是对泛型类型的类型参数的约束,而不是对您正在调用的泛型方法的类型参数的约束。
例如:
因此,如果您尝试调用
Foo
现在,在上面的情况下,约束是完全相同的......但它们不必如此。例如,请考虑:
如果您尝试调用
Foo(null),该方法仍将是候选集的一部分 - 因为当
TItem
为object
,Factory
中表达的约束仍然成立,并且这是在构建候选集时检查的内容。如果这被证明是最好的方法,那么稍后在 7.6.5.1 的结束附近它就会失败:Eric 的博客文章< /a> 包含更多详细信息。
EDIT: I've now blogged about this in more detail.
My original (and I now believe incorrect) thought: generic constraints aren't taken into account during the overload resolution and type inference phases - they're only used to validate the result of the overload resolution.
EDIT: Okay, after a lot of going round on this, I think I'm there. Basically my first thought was almost correct.
Generic type constraints only act to remove methods from a candidate set in a very limited set of circumstances... in particular, only when the type of a parameter itself is generic; not just a type parameter, but a generic type which uses a generic type parameter. At that point, it's the constraints on the type parameters of the generic type which are validated, not the constraints on the type parameters of the generic method you're calling.
For example:
So if you try to call
Foo<object>(null)
the above method won't be part of the candidate set, becauseNullable<object> value
fails to satisfy the constraints ofNullable<T>
. If there are any other applicable methods, the call could still succeed.Now in the case above, the constraints are exactly the same... but they needn't be. For example, consider:
If you try to call
Foo<object>(null)
, the method will still be part of the candidate set - because whenTItem
isobject
, the constraint expressed inFactory<TItem>
still holds, and that's what's checked when building up the candidate set. If this turns out to be the best method, it will then fail validation later, near the end of 7.6.5.1:Eric's blog post contains more detail on this.
埃里克·利珀特 (Eric Lippert) 的解释比我更好,此处。
我自己也遇到过这个情况。我的解决方案是
Eric Lippert explains better than I ever could, here.
I have come across this myself. My solution was
我发现这种“有趣”的奇怪方法在 .NET 4.5 中使用默认参数值来做到这一点:) 也许对于教育\推测目的比实际使用更有用,但我想展示它:
I found this "interesting" strange way to do that in .NET 4.5 using default parameter values :) Maybe is more useful for educational\speculative purposes than for real use but I would like to show it :