给定这个“IHandle”接口和两个要处理的类:
interface IHandle<T>
{
void Handle(T m);
}
class M1
{
public int Id;
}
class MReset
{
}
我想创建一个通用基础,负责“重置”以及管理M1实例:
class HandlerBase<T> :
IHandle<MReset>,
IHandle<T> where T : M1
{
protected int Count;
void IHandle<T>.Handle(T m)
{
++Count;
Console.WriteLine("{0}: Count = {0}", m.Id, Count);
}
void IHandle<MReset>.Handle(MReset m)
{
Count = 0;
}
}
这不编译,因为编译器认为T可以是“MReset”,因此它输出:
错误CS0695:'HandlerBase'无法同时实现'IHandle' 和'IHandle',因为他们可能统一某些类型参数 取代
这本身就有些奇怪,因为我无法看到T可能是MReset类型,因为它必须是M1类型。但好吧,我可以接受编译器比我聪明: - )
编辑:编译器并不比我聪明:-)根据对Why does this result in CS0695?的评论,我们有“在确定所有可能的构造类型时不考虑约束声明”。
现在我交换了接口声明:
class HandlerBase<T> :
IHandle<T> where T : M1,
IHandle<MReset>
{
... same as before ..
}
突然间我收到一条不同的错误消息,指出我无法实现IHandle.Handle(MReset m),因为类声明没有声明它正在实现该接口:
错误CS0540:'HandlerBase.IHandle&lt; ...&gt; .Handle(MReset)':含有 type没有实现接口'IHandle'
问题:为什么声明的顺序会有所不同?第二个例子出了什么问题?
最后证明有一个解决方案:
class HandlerBase :
IHandle<MReset>
{
protected int Count;
void IHandle<MReset>.Handle(MReset m)
{
Count = 0;
}
}
class Handler<T> : HandlerBase,
IHandle<T> where T : M1
{
void IHandle<T>.Handle(T m)
{
++Count;
Console.WriteLine("{0}: Count = {0}", m.Id, Count);
}
}
但该解决方案仅在HandlerBase
实现IHandle<MReset>
时才有效 - 如果首先在IHandle<T>
中实现通用接口HandlerBase
则不行。的为什么
修改:在IHandle<T>
中实施HandlerBase
工作(如果我显示了某人可能已经看过的代码)。这有效:
class HandlerBase<T> :
IHandle<T> where T : M1
{
protected int Count;
void IHandle<T>.Handle(T m)
{
++Count;
Console.WriteLine("Type = {0}, Id = {1}, Count = {2}", GetType(), m.Id, Count);
}
}
class Handler<T> : HandlerBase<T>,
IHandle<MReset>
where T : M1
{
void IHandle<MReset>.Handle(MReset m)
{
Count = 0;
Console.WriteLine("RESET");
}
}
不幸的是,我的第二课声明是:
class Handler<T> : HandlerBase<T> where T : M1,
IHandle<MReset>
{
void IHandle<MReset>.Handle(MReset m)
{
Count = 0;
Console.WriteLine("RESET");
}
}
注意where T : M1
位置的微妙差异:-)最后一个例子声明T必须实现IHandle<MReset>
(除M1
之外)。杜!
答案 0 :(得分:1)
C#语言规范(https://www.microsoft.com/en-us/download/confirmation.aspx?id=7029)讨论了实现的接口的唯一性&#34;在13.4.2中:&#34;通用类型声明实现的接口必须对所有可能的构造类型保持唯一。&#34;稍后,在描述检查的详细信息时:&#34;在确定所有可能的构造类型时,不会将约束声明视为。&#34;
为什么会这样,我不确定;或许可以构造嵌套或链式约束,这使得编译器无法证明唯一性,或者不能通过程序集传递所有约束(我认为这对于通用语言规则是必要的)。
答案 1 :(得分:1)
问题解决了 - 我发现了微妙的差异。当交换声明的顺序时,我应该不移动where T : M1
,因为IHandle<MReset>
约束最终会应用于T而不是类声明:
class HandlerBase<T> :
IHandle<T> where T : M1,
IHandle<MReset>
{
... same as before ..
}
正确的重新排序应该是:
class HandlerBase<T> :
IHandle<T>,
IHandle<MReset>
where T : M1
{
... same as before ..
}