给定这个“IHandle”接口(interface)和两个要处理的类:
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”,所以它输出:
error CS0695: 'HandlerBase' cannot implement both 'IHandle' and 'IHandle' because they may unify for some type parameter substitutions
这本身有点奇怪,因为我看不出 T 怎么可能是 MReset 类型,因为它必须是 M1 类型。但是好吧,我可以接受编译器比我聪明:-)
编辑:编译器并不比我聪明 :-) 根据 Why does this result in CS0695? 上的评论我们有“在确定所有可能的构造类型时不考虑约束声明”。
现在我交换接口(interface)声明:
class HandlerBase<T> :
IHandle<T> where T : M1,
IHandle<MReset>
{
... same as before ..
}
突然我收到一条不同的错误消息,指出我无法实现 IHandle.Handle(MReset m) 因为类声明没有声明它正在实现该接口(interface):
error CS0540: 'HandlerBase.IHandle<...>.Handle(MReset)': containing type does not implement interface '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>
- 不是通用接口(interface)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
)。呸!
最佳答案
问题已解决 - 我发现了细微差别。当交换声明的顺序时,我应该不移动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 ..
}
关于c# - 实现通用接口(interface)时奇怪的 C# 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29843666/