C#中通用接口的子类型

时间:2013-04-24 11:32:21

标签: c# generics subtyping

我有一个包含一些数据的“最小状态”类型,可以生成另一个最小状态的实例:

public interface IMinimalState
{
   IMinimalState generate();
   int getData();
}

我还有一个包含更多数据的“正常状态”,可以生成正常状态的实例:

public interface IState
{
   IState generate();
   int getData();
   int getAnotherData();
}

据我所知,IState应该是IMinimalState的子类型。 (任何需要IMinimalState的东西在获得IState时应该同样高兴)但是,我不能让编译器接受它。

示例:

   public interface IMinimalState
   {
      IMinimalState generate();
      int getData();
   }

   public interface IState : IMinimalState
   {
      int getAnotherData();
   }

   public class MinimalState : IMinimalState
   {
      public IMinimalState generate() { return this; }
      public int getData() { return 0; }
   }

   public class State : IState
   {
      public IState generate() { return this; }  //Compiler Error, return type should be IMinimalState
      public int getData() { return 1; }
      public int getAnotherData() { return 2; }
   }

很公平,让我们尝试通用接口:

   public interface IMinimalState<out T> where T : IMinimalState<T>
   {
      T generate();
      int getData();
   }

   public interface IState<out T> : IMinimalState<T> where T : IState<T>
   {
      int getAnotherData();
   }

   public class MinimalState : IMinimalState<MinimalState>
   {
      public MinimalState generate() { return this; }
      public int getData() { return 0; }
   }

   public class State : IState<State>
   {
      public State generate() { return this; }
      public int getData() { return 1; }
      public int getAnotherData() { return 2; }
   }

尚未编译错误。但State仍然不是MinimalState的子类型,IState<State>不是IMinimalState<MinimalState>的子类型。我尝试了很多其他组合但没有成功。

有没有办法让IState成为IMinimalState的子类型?如果没有,

  • 是不是因为.Net类型系统不够强大?

  • 或者,我认为IState实际上是IMinimalState的子类型是错误的吗? (如果某个需要IMinimalState的内容收到IState,该程序会崩溃吗?)

4 个答案:

答案 0 :(得分:2)

您可以使用new关键字更改generate的返回类型,然后在generate

中实现State的两种变体形式
   public interface IMinimalState
   {
      IMinimalState generate();
      int getData();
   }

   public interface IState : IMinimalState
   {
      new IState generate();      
      int getAnotherData();
   }

   public class State : IState
   {
      public IState generate() { return this; } 
      IMinimalState IMinimalState.generate() { return  generate(); }           
      ...
   }

答案 1 :(得分:1)

如果您更改了返回类型 - 您正在更改the contract - 则无法使用IMinimalState对其进行建模。

我只是简化一下,例如

public interface IMinimalState
{
    IMinimalState generate();
    int getData();
}

public interface IState : IMinimalState
{
    // IState generate();
    int getAnotherData();
}

public class MinimalState : IMinimalState
{
    public IMinimalState generate() { return this; }
    public int getData() { return 0; }
}

public class State : IState
{
    IMinimalState IMinimalState.generate() { return this.generate(); }
    // IState IState.generate() { return this; }
    public IState generate() { return this; }
    public int getData() { return 1; }
    public int getAnotherData() { return 2; }
}

注意:您的'用例'在这里至关重要(并且缺失) - 并推动您的设计。你应该在做出设计决定之前提供它,这可能是第一件事。

通常,如果您在基础接口IMinimalState上存储和迭代 - 这就是您所需要的。

如果您正在访问knowing对象State,则可以使用其公共方法获取强类型。

如果你仍然想要 - 你可以同时拥有它们(只需取消注释这两行)。

最后一个选项 - 经常用于更复杂的情况 - 是使用Visitor来区分IMinimalState和IState - 当你只有一个基本接口列表时。例如。你需要redefine类型的参数,子表达式等表达式使用它。如果你感兴趣我可以稍后发布。

答案 2 :(得分:0)

您需要返回IMinimalState,因为这是界面所说的。

public class State : IState
{
  public IMinimalState generate() { return this; }  // Fixed
  public int getData() { return 1; }
  public int getAnotherData() { return 2; }
}

如果您以后需要在IMinimalState的引用上访问IState成员,则需要将其强制转换

var state = minimalState as IState;
if (state != null)
{
    // Work on IState
}

答案 3 :(得分:0)

您可以使用泛型:

public interface IMinimalState<T>
{
    T generate();
    int getData();
}

public interface IState : IMinimalState<IState>
{
    IState generate();
    int getAnotherData();
}