我当前的非编译代码与此类似:
public abstract class A { }
public class B { }
public class C : A { }
public interface IFoo<T>
{
    void Handle(T item);
}
public class MyFoo<TA> : IFoo<TA>, IFoo<B>
    where TA : A
{
    public void Handle(TA a) { }
    public void Handle(B b) { }
}
C#编译器拒绝编译它,引用以下规则/错误:
'MyProject.MyFoo <TA>'无法同时实现'MyProject.IFoo <TA>'和'MyProject.IFoo <MyProject.B>',因为它们可能会统一某些类型参数替换
我理解这个错误意味着什么; 如果TA可以是任何东西那么它在技术上也可能B会引入两种不同Handle实现的模糊性.
但TA 不可能是任何东西.基于类型层次结构,TA 不能是B- 至少,我不认为它可以.  TA必须派生自A,而不是派生出来B,显然在C#/ .NET中没有多类继承.
如果我删除泛型参数和替换TA用C,甚至A,它编译.
那么为什么我会收到这个错误?这是编译器中的错误或一般的非智能,还是我还缺少其他东西?
是否有任何解决方法或我只是必须MyFoo为每个可能的TA派生类型重新实现泛型类作为单独的非泛型类?
Eri*_*ert 48
这是C#4规范第13.4.2节的结果,该规范规定:
如果从C创建的任何可能的构造类型将类型参数替换为L后,导致L中的两个接口相同,则C的声明无效.在确定所有可能的构造类型时,不考虑约束声明.
注意那里的第二句话.
因此,它不是编译器中的错误; 编译器是正确的.有人可能会说这是语言规范中的一个缺陷.
一般而言,在几乎所有必须推断出关于泛型类型的事实的情况下,忽略约束.约束主要用于确定泛型类型参数的有效基类,而其他几乎没有.
不幸的是,正如您所发现的那样,这有时会导致语言不必要的严格.
一般来说,两次实现"相同"接口的代码气味很差,在某种程度上只能通用泛型类型参数来区分.例如,有一个奇怪的class C : IEnumerable<Turtle>, IEnumerable<Giraffe>东西 - 它既是C又是一系列的乌龟和一系列长颈鹿,同时呢?你能描述一下你在这里想要做的事情吗?可能有更好的模式来解决真正的问题.
实际上,您的界面与您描述的完全一致:
interface IFoo<T>
{
    void Handle(T t);
}
然后接口的多重继承提出了另一个问题.你可能会合理地决定使这个界面逆变:
interface IFoo<in T>
{
    void Handle(T t);
}
现在假设你有
interface IABC {}
interface IDEF {}
interface IABCDEF : IABC, IDEF {}
和
class Danger : IFoo<IABC>, IFoo<IDEF>
{
    void IFoo<IABC>.Handle(IABC x) {}
    void IFoo<IDEF>.Handle(IDEF x) {}
}
而现在事情变得非常疯狂......
IFoo<IABCDEF> crazy = new Danger();
crazy.Handle(null);
Handle的哪个实现被称为 ???
有关此问题的更多想法,请参阅此文章和评论:
显然,它是按照Microsoft Connect中讨论的设计进行的:
解决方法是,将另一个接口定义为:
public interface IIFoo<T> : IFoo<T>
{
}
然后将其实现为:
public class MyFoo<TA> : IIFoo<TA>, IFoo<B>
    where TA : A
{
    public void Handle(TA a) { }
    public void Handle(B b) { }
}
它现在编译精细,单声道.
如果将一个接口放在基类上,则可以将其隐藏起来。
public interface IFoo<T> 
{
}
public class Foo<T> : IFoo<T>
{
}
public class Foo<T1, T2> : Foo<T1>, IFoo<T2>
{
}
我怀疑这是有效的,因为如果类型确实“统一”,那么很明显派生类的实现获胜。