假设我们有两个不相关的接口(interface)
public interface IFirst
{
}
public interface ISecond
{
}
以及具有相同名称但受限于每个接口(interface)的扩展方法。
public static class IFirstExtensions
{
public static void DoIt<TFirst>(this TFirst model)
where TFirst : IFirst
{
}
}
public static class ISecondExtensions
{
public static void DoIt<TSecond>(this TSecond model)
where TSecond : ISecond
{
}
}
当我尝试使用 IFirst 实例时:
IFirst first = ...;
first.DoIt();
然后我得到错误:
"CS0121 The call is ambiguous between the following methods or properties: 'IFirstExtensions.DoIt(TFirst)' and 'ISecondExtensions.DoIt(TSecond)'".
这很奇怪。看起来这两种方法在此范围内都是可见的。但如果我给它们取不同的名字,例如:
public static class IFirstExtensions
{
public static void DoFirst<TFirst>(this TFirst model)
where TFirst : IFirst
{
}
}
public static class ISecondExtensions
{
public static void DoSecond<TSecond>(this TSecond model)
where TSecond : ISecond
{
}
}
然后约束起作用,第二种方法不可见并引发编译错误:
IFirst first = ...;
first.DoSecond();
所以看起来约束稳定条件在检测歧义和调用时的工作方式不同。但是在 C# 规范中,我发现只有一章与这个主题相关,严格描述了约束是如何工作的。这是编译器中的错误还是我遗漏了什么?
最佳答案
通用约束不是方法签名的一部分。这两种方法在重载解析方面完全相同,因此会产生一个模糊的调用错误。
Specifically, the signature of a method consists of its name, the number of type parameters and the number, modifiers, and types of its formal parameters (C# 5.0 Specification, 10.6 Methods)
For the purposes of signature comparisons any type-parameter-constraints-clauses are ignored, as are the names of the method’s type-parameters, but the number of generic type parameters is relevant (ECMA-334, 25.6.1 Generic method signatures)
说得更清楚一点,当涉及到重载决议时,两种扩展方法都是简单的:
public static void DoFirst<T>(this T model)
另外,请注意该问题不仅仅与扩展方法有关。考虑以下示例,其中在同一类中声明了两个具有相同签名但不同约束的泛型方法:
class Foo
{
void Bar<T>(Blah blah) where T: Frob { }
void Bar<T>(Blah blah) where T: Blob { } //CS0111 error
}
你会得到一个编译时错误:
CS0111 Type 'Foo' already defines a member called 'Bar' with the same parameter types.
关于c# - 受约束的扩展方法产生模棱两可的调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45903399/