【发布时间】:2015-07-02 19:58:24
【问题描述】:
给定这个“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<...>.Handle(MReset)': 包含 类型未实现接口“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 中实现则无效。 为什么?
编辑:在HandlerBase 中实现IHandle<T> 确实 工作(如果我展示了代码,有人可能已经看到了)。这有效:
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)。呵呵!
【问题讨论】:
-
Related / Duplicate。我并没有因为这个问题“为什么声明的顺序会产生如此大的差异?”而关闭重复。那里没有回答。
-
确实是相关链接。我刚刚在那里编辑了接受的答案,以使 C# 规范中的重要信息更加可见:“在确定所有可能的构造类型时不考虑约束声明。”
标签: c# generics inheritance interface