c# - 两个 C# 扩展泛型方法之间的调用不明确,其中 T :class and other where T:struct

标签 c# .net extension-methods generics

考虑两种扩展方法:

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 是一个类,而不是一个结构?

最佳答案

编辑:我现在 blogged about this更详细。


我原来的(我现在认为是不正确的)想法:在重载决议和类型推断阶段不考虑泛型约束 - 它们仅用于验证重载决议的结果。

编辑:好的,经过很多 的讨论后,我想我已经到了。基本上我的第一个想法几乎是正确的。

通用类型约束仅用于在非常有限的情况下从候选集中删除方法...特别是,仅当参数本身的类型是通用的时;不仅仅是一个类型参数,而是一个使用泛型类型参数的泛型类型。此时,验证的是泛型类型类型参数的约束,而不是您调用的泛型方法的类型参数的约束。

例如:

// Constraint won't be considered when building the candidate set
void Foo<T>(T value) where T : struct

// The constraint *we express* won't be considered when building the candidate
// set, but then constraint on Nullable<T> will
void Foo<T>(Nullable<T> value) where T : struct

因此,如果您尝试调用 Foo<object>(null)上述方法不会成为候选集的一部分,因为Nullable<object> value未能满足 Nullable<T> 的约束.如果有任何其他适用的方法,调用仍然可以成功。

现在在上面的例子中,约束是完全一样的……但它们不一定是。例如,考虑:

class Factory<TItem> where TItem : new()

void Foo<T>(Factory<T> factory) where T : struct

如果您尝试调用 Foo<object>(null) ,该方法仍将是候选集的一部分 - 因为当 TItemobject ,在 Factory<TItem> 中表示的约束仍然成立,这就是在建立候选集时要检查的内容。如果这被证明是最好的方法,它会在稍后验证失败,接近 7.6.5.1 的结束:

If the best method is a generic method, the type arguments (supplied or inferred) are checked against the constraints (§4.4.4) declared on the generic method. If any type argument does not satisfy the corresponding constraint(s) on the type parameter, a binding-time error occurs.

埃里克的 blog post包含有关此的更多详细信息。

关于c# - 两个 C# 扩展泛型方法之间的调用不明确,其中 T :class and other where T:struct,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4014036/

相关文章:

C# 变量初始化与赋值

c# - 在 EventHandler 中对发送者对象进行单元测试

c# - 扩展已经继承另一个类的类

c# - POST 字符串到 ASP.NET Web Api 应用程序 - 返回 null

c# - 在 .NET 中读取文件内容更改

C# - 在本地安全地存储密码

c# - 在不指定尽可能多的类型的情况下调用通用扩展方法

c# - 向菜单条添加标签

c# - 从 DataTemplate UWP 绑定(bind) UserControl DP

c# - "Use Extension Methods Sparingly?"背后的动机是什么