【问题标题】:Cannot use polymorphism because of generic base class由于泛型基类,无法使用多态性
【发布时间】:2010-10-16 13:54:40
【问题描述】:

我只用一种方法创建了没有字段的基本泛型类

public class Base<T> where T:class
{
  public static T Create()
  {
     // create T somehow
  }
}

public class Derived1 : Base<Derived1>
{
}

public class Derived2 : Base<Derived2>
{
}


public class Program
{
    bool SomeFunction()
    {
     // Here I need reference to base class
     Base baseref; // error here 

     switch(somecondition)
     {
       case 1:
        baseref = Derived1.Create();
       break;

       case 2:
        baseref = Derived1.Create();
       break

     }

     // pass baseref somewhere     
    }
}

一个明显的选择是将基类转换为接口,但这是不可能的,因为接口不能包含静态方法。

我想我需要一些中间基类。请推荐

【问题讨论】:

  • 你得到什么样的错误? “base”(小写)是 C# 中的关键字。
  • 而且您似乎没有指定非泛型类“Base”。
  • Marijn,好的,让我们用 var1 替换 base
  • 请您解释一下您想要实现的究竟是什么,而不是陷入语言机制和机制中。也许这不是最好的方法?
  • 您的 SomeFunction() 方法在类之外 - 它不会编译。它应该在哪个班级?

标签: c# generics polymorphism


【解决方案1】:

您必须从 Base 类中删除泛型参数,您可以将其移至 Create 方法:

public class Base 
{
    public static T Create<T>() where T : class
    {
        return Activator.CreateInstance<T>();
    }
}

public class Derived1 : Base
{
}

public class Derived2 : Base
{
}

【讨论】:

  • 看起来不错,但是如果有没有模板方法的解决方案呢?
  • 这取决于,如果您希望您的 Create 方法返回您需要模板的特定类型 T,但如果您可以从 Create 方法返回 Base 您可以发送一个枚举或字符串或其他东西来定义您要创建的类型。
  • 现在工厂方法可以创建任何东西的实例。要将其限制为派生类型,作者需要指定 where T : Base 而不是 class
【解决方案2】:

初步评估

有了这个声明,

public class Derived1 : Base<Derived1> {

根据基类,您以两种不同的方式使用 Derived1。

您实际上是在告诉 C# 编译器 Derived1 两者:

  1. 继承基础
  2. 和 Base 通过非继承方式使用 Derived1 的实例。

这并没有错(如果这是您真正想要的),但对于大多数编程场景来说这是不寻常的;您通常选择其中之一。但是,您的逻辑的好处是:您不仅通过继承拥有 Derived1 的隐式实例(对于任何其他派生类都相同),而且基类也可以处理相同派生的其他外部实例通过类型参数&lt;T&gt;输入

我在基类中看到的一个问题是,当按预期使用工厂方法时,它会变成一种循环场景,因为要支持所有派生类,它需要支持class Base&lt;T&gt; where T:Base&lt;T&gt; 之类的东西。这几乎是不可能宣布的,因为您必须以循环方式说:Base&lt;Base&lt;Base&lt;!!!&gt;&gt;&gt; baseref = null; where !!!代表无限数量的相同。


一个解决方案...

一种可能(也是强有力的解决方案)是将 Type 参数从类移至工厂 Create 方法,并将其使用限制为 Base 类类型,如下所示:

using System;

public abstract class Base 
{
    public static T Create<T>() where T : Base
    {
        return Activator.CreateInstance<T>();
    }

}

注意:我已经将基类抽象化,它将实例化限制为派生类型;但是您仍然可以使用基类引用(请参阅下面的 switch 语句用法)。

这些派生类仍然从基类继承。

public class Derived1 : Base
{
}

public class Derived2 : Base
{
}

您的工厂方法仅限于创建派生类型的实例。逻辑已被交换,因此派生类型被赋予工厂方法,而不是在其上调用工厂方法。

public class Program
{
    bool SomeFunction()
    {

    Base baseref = null;

     switch(DateTime.Now.Second)
     {
       case 1:
        baseref = Base.Create<Derived1>();  // OK
       break;

       case 2:
        baseref = Base.Create<Derived2>();  //OK
        break;

       case 60:
        baseref = Base.Create<string>(); //COMPILE ERR - good because string is not a derived class
        break;
     }

     // pass baseref somewhere     
    }
}

【讨论】:

    【解决方案3】:
    public abstract class Base
    {
    }
    
    public class Base<T> : Base where T : class
    {
        public static T Create()
        {
            // create T somehow
        }
    }
    
    public class Derived1 : Base<Derived1>    // also inherits non-generic Base type
    {
    }
    
    public class Derived2 : Base<Derived2>    // also inherits non-generic Base type
    {
    }
    

    【讨论】:

    • 酷!谢谢,正是我需要的!一个简单的解决方案,但我只是卡住了
    • 在这种情况下,我通常让通用基类实现一个接口。在我看来,这比其他等效方法更干净。
    • @steinar:在大多数情况下,我可能也会选择一个接口,但是 OP 在问题的其他地方暗示他们需要一个类,所以这就是我在这个例子。
    【解决方案4】:

    如何创建一个接口并让抽象类实现该接口?

    【讨论】:

      猜你喜欢
      • 2011-07-10
      • 1970-01-01
      • 2019-08-12
      • 2023-03-05
      • 1970-01-01
      • 2023-03-29
      • 2017-05-14
      • 2012-06-05
      • 2021-02-28
      相关资源
      最近更新 更多