【问题标题】:C# Derive From Generic Base Class (T : U<T>)C# 派生自通用基类 (T : U<T>)
【发布时间】:2015-07-14 07:19:11
【问题描述】:

我正在尝试找到一种从通用基类派生类的方法。说:

sealed public class Final : Base<Something>
{

}

public class Base<T> : T
    where T : Anything // <-- Generics do not allow this
{

}

在 C# 中这似乎是不可能的。

还有其他解决方案可以实现类似的效果吗?

我找到了这个StackOverflow question,但它似乎并没有解决问题,或者至少我不明白它应该如何解决。

编辑:

我希望得到的结果是能够做这样的事情:

Anything[] anything;
//Assign some Instances to anything 

foreach(Final final in anything){
     //do something with final
}

【问题讨论】:

  • 如果你想在foreach中使用它,你需要实现IEnumerable&lt;Final&gt;
  • @juharr 在我上面的编辑中,“任何东西”是一个数组。所以我不需要这样做。
  • @juharr 只需一个MoveNextCurrent 方法就足够了,无需实现整个IEnumerable 接口。
  • 您想要做的事情在逻辑上不合理,也不会奏效。当它的值在运行时建立时,您不能从类型参数派生。例如,您如何知道可以覆盖哪些方法?我认为您需要重新考虑您的设计,以便您从T 的任何类型派生,然后在实例化Base 时使用DerivedT,而不是尝试从Base&lt;T&gt; 中的T 派生。这有意义吗?

标签: c# generics inheritance dynamic


【解决方案1】:

我希望得到的结果是能够做这样的事情:

 Anything[] anything;
 //Assign some Instances to anything 

 foreach(Final final in anything){
     //do something with final
 }

您的foreach 循环表明:class Anything : Final { … }

这显然会按照您的计划和命名来改变继承层次结构。 (您的继承关系中不能有循环)。


public class Base<T> : T where T : Anything { …

让我稍微详细说明一下这部分。我会将您的示例进一步简化为 class Base&lt;T&gt; : T

这是不可能的,有充分的理由。想象一下:

class Base<T> : T
{
    public override string Frobble()
    {
        Fiddle();
        return "*" + base.Frobble() + "*";
    }
}

class A
{
    public sealed string Frobble() { … }
}

class B
{
}

class C
{
    public virtual string Frobble() { … }
}

abstract class D
{
    public abstract void Fiddle();
    public virtual string Frobble() { … }
}

class E
{
    public void Fiddle() { … }
    public virtual string Frobble() { … }
}

如果class Base&lt;T&gt; : T 被允许,你会遇到各种荒谬的情况。

  • Base&lt;A&gt; 会很荒谬,因为Frobble 不能在派生类中被覆盖。
  • Base&lt;B&gt; 将是荒谬的,因为你不能覆盖一个方法 基类中不存在。
  • Base&lt;C&gt; 不起作用,因为没有可调用的 Fiddle 方法。
  • Base&lt;D&gt; 不起作用,因为您不能调用抽象方法。
  • 只有Base&lt;E&gt; 可以工作。

编译器怎么会知道如何正确编译Base&lt;T&gt; 并分析依赖它的代码?

关键是您不能从编译时未知的类派生。 T 是一个参数,即一个变量,一个占位符。所以class Base&lt;T&gt; : T 基本上就像在说,Base&lt;T&gt; 继承自某个(未知)类”。类继承是一种类型关系,需要在编译时知道所涉及的类型。 (实际上,这不是一个超精确的声明,因为您可以从诸如class SpecialList&lt;T&gt; : List&lt;T&gt; 之类的泛型类型继承。但至少,派生类必须知道哪些成员(方法、属性等)在基类。)

【讨论】:

    【解决方案2】:

    这是你想要的吗?

    sealed public class Final : Base<int>{
    
    }
    
    public class Base<T> {
    
    }
    

    【讨论】:

    • Base 现在应该派生自 ,在这种情况下是 int
    • @NoelWidmer 这就是所谓的泛型约束,您可以在其中放置条件来限制类型 T。
    【解决方案3】:

    只有当Final 也是一个泛型类时,你才能这样做,就像这样:

    public sealed class Final<T> : Base<T>
    

    然后您可以在T 上设置类型限制,作为class,仅允许引用类型为T,或Base&lt;T&gt; 的实例,以仅允许从Base&lt;T&gt; 派生的类型:

    public class Base<T> where T : Base<T>
    

    【讨论】:

      【解决方案4】:

      我不知道这个问题的上下文,但是我在一个项目中遇到了同样的问题,我必须能够扩展已经由许多其他人派生的基类。喜欢:

      abstract class Base {}
      class FinalA : Base {}
      class FinalB : Base {}
      
      // Now create extended base class and expect final classes to be extended as well:
      class BetterBase : Base {}
      

      解决方案是创建共同祖先并通过属性连接:

      abstract class Foundation {}
      abstract class Base : Foundation 
      {
          Foundation Final { get; }
      }
      class FinalA : Foundation {}
      class FinalB : Foundation {}
      class FinalC : Foundation
      {
          Foundation Base { get; }
      }
      
      // Here's the desired extension:
      class BetterBase : Base {}
      

      现在 BetterBase 已连接到 final 类,如果需要,final 类也可以与 (Better)Base 连接,如 FinalC 类所示。

      【讨论】:

        猜你喜欢
        • 2018-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-05
        • 1970-01-01
        • 2010-10-22
        • 1970-01-01
        相关资源
        最近更新 更多