我最近写了这篇文章并且惊讶于它编译:
public class MyGeneric<U, V> {
MyGeneric(U u) { ... }
MyGeneric(V v) { ... }
public void Add(U u, V v) { ... }
public void Add(V v, U u) { ... }
}
如果我按如下方式使用此类,如果我调用Add,则会出现“不明确的构造函数引用”和“不明确的调用”。
var myVar = new MyGeneric<int, int>(new MyIntComparer());
显然,当我使用int和double作为泛型类型时,没有歧义,当然,当我同时使用两个整数时,也会分配给一个双精度。
var myVar = new MyGeneric<int, double>(new MyIntComparer());
myVar.Add(3, 5);
然后我认为以下内容也被允许,但令人惊讶的是我收到了错误。为什么以下不允许编译?
public interface IMyInterface<T, S> {
void Add(T t, S s);
}
public class MyGeneric<U, V> : IMyInterface<U, V>, IMyInterface<V, U> {
public MyGeneric(U u) { }
public MyGeneric(V v) { }
void IMyInterface<U, V>.Add(U u, V v) { ... }
void IMyInterface<V, U>.Add(V v, U u) { ... }
}
无论我使用隐式还是显式接口实现,编译器都会声明
'MyGeneric&LT; U,V&GT;'不能同时实现'IMyInterface&lt; U,V&gt;'和'IMyInterface&lt; V,U&gt;'因为他们可能统一某些类型参数替换
为什么第一个允许写?
答案 0 :(得分:4)
1-为什么以下不允许编译?
C#4规范的第13.4.2节规定:
必须保留由泛型类型声明实现的接口 所有可能的构造类型都是唯一的没有这个规则,它会 无法确定正确的方法来确定 构造类型。
2-为什么第一个允许写?
编译器在编译时执行泛型类型检查,C#4规范的7.4.3.5节说明:
虽然声明的签名必须是唯一的,但有可能 类型参数的替换导致相同的签名。在 在这种情况下,上面的超载解决方案的打破规则将会 选择最具体的成员。以下示例显示了重载 根据此规则有效且无效:
interface I1<T> {...}
interface I2<T> {...}
class G1<U>
{
int F1(U u); // Overload resulotion for G<int>.F1
int F1(int i); // will pick non-generic
void F2(I1<U> a); // Valid overload
void F2(I2<U> a);
}
class G2<U,V>
{
void F3(U u, V v); // Valid, but overload resolution for
void F3(V v, U u); // G2<int,int>.F3 will fail
void F4(U u, I1<V> v); // Valid, but overload resolution for
void F4(I1<V> v, U u); // G2<I1<int>,int>.F4 will fail
void F5(U u1, I1<V> v2); // Valid overload
void F5(V v1, U u2);
void F6(ref U u); // valid overload
void F6(out V v);
}
答案 1 :(得分:1)
这是语言规范的一部分,正如在此接受的答案中所解释的那样:
C#4规范的第13.4.2节规定:
如果从C创建的任何可能的构造类型将类型参数替换为L后,导致L中的两个接口相同,则C的声明无效。在确定所有可能的构造类型时,不考虑约束声明。
我猜你的两个例子之间的区别在于第二个使用接口(根据语言规范检查重复项)但是第一个使用类型(没有检查重复项,尽管可能会引起歧义,如你所见)。