c# - 实现通用接口(interface)时奇怪的 C# 行为

标签 c# generics inheritance interface

给定这个“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 : M1IHandle<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/

相关文章:

c# - FtpWebRequest TLS 连接是否需要客户端证书?

Java泛型方法问题

delphi - 通用工厂

Java 泛型类型扩展多个类

c++ - Qt 基类函数定义

Java使用基类来继承本地方法

java - 将访问器和修改器方法从一个类移至其父类(super class)

c# - 如何在C#中写保护USB驱动器

C# 使用任何类型的对象作为函数参数

c# - Paypal 更改默认货币