通用类型,其类型参数是抽象基类

时间:2014-01-31 14:47:41

标签: c# generics abstract-class

假设我有一个名为Animal基类和两个名为LionTiger派生类。我还想要一个名为AnimalList<Animal>泛型类型来包含Animal的成员。例如:

var list = new AnimalList<Animal>();

list.Add(new Lion());
list.Add(new Tiger());

到目前为止非常简单,但有一个问题......我希望基类Animalabstract。也就是说,我不想允许创建基类的实例。但是,使基类抽象不出意外会导致错误CS0310(请参阅下面的完整示例)。

我确实提出了一个解决方案:根据需要使基类非抽象,只需从默认(无参数)构造函数中抛出异常:

public Animal()
{
    throw new System.NotImplementedException();
}

但这让我感到有点不安。 有更好的方法吗?


这是一个完整的例子,说明了我在上面描述的场景:

// public class Animal {}        // OK
public abstract class Animal {}  // 'abstract' keyword causes error 'CS0310'

public class Lion : Animal {}
public class Tiger : Animal {}

public class AnimalList<T> :
    Animal
    where T : Animal, new()
{
    public void Add(T animal) {}
}

class AnimalListDemo
{
    static public void Main(string[] args)
    {
        // The following statement causes:
        // error CS0310 - 'Animal' must be a non-abstract type with a
        // public parameterless constructor in order to use it as
        // parameter 'T' in the generic type or method 'AnimalList<T>'

        var list = new AnimalList<Animal>();

        list.Add(new Lion());
        list.Add(new Tiger());
    }
}

4 个答案:

答案 0 :(得分:4)

只需删除new()约束即可。它要求你提供一个可以通过new()实例化的类(这就是要求的全部内容),但是抽象类显然不能这样做。

来自MSDN

  

新约束指定泛型类声明中的任何类型参数都必须具有公共无参数构造函数。 要使用新约束,类型不能是抽象的

答案 1 :(得分:2)

是否必须对泛型参数设置new()约束?如果您将其删除,则会进行编译,但代价是不允许在T内创建AnimalList的新实例。

原因在于,如果您要求类具有公共的无参数构造函数,则它不能是抽象的,因为抽象类特别是不可创建的,但是您要求该类可以创建new()。由于这些要求相互矛盾,编译器会抱怨。

解决方案似乎是一个hack,并且也不会工作,因为派生类构造函数也将调用基类构造函数(而不是完全覆盖它)并仍然抛出异常。

答案 2 :(得分:1)

在我的问题结束时,我问道:

  

有更好的方法吗?

我在本页的有用答案中得出结论:是!

特别是,在他对我的问题的评论中,@ CodeInChaos说了以下内容:

  

一般来说,我会认为new()约束有点代码味道。

这让我找到了new()约束的替代方法。 (我确实需要在我的类层次结构中的基类中创建泛型类型参数的实例。)

我在Create a new instance of T without the new constraint的答案中找到了我要找的东西:

var instanceOfT = new T(); // Before

var instanceOfT = (T)Activator.CreateInstance(typeof(T)); // After

这使我放弃了源代码中的几个new()约束。最后,删除new()约束允许我根据需要将中间类设置为abstract

答案 3 :(得分:0)

允许将接口与new约束组合:

public interface IAnimal {}

public abstract class Animal : IAnimal {} 

public class AnimalList<T> where T : IAnimal, new() {}

但是,您的第一行仍会失败:

var list = new AnimalList<Animal>();

AnimalList<Animal>(或AnimalList<IAnimal>)不是有效类型,因为无法构造给定的T。您确定new是您想要的吗?