2013-05-28 53 views
9

如果这些实现没有默认构造函数,是否可以将类型参数限制为抽象类的具体实现?添加类型参数约束以防止抽象类

举例来说,如果我有:

public abstract class Animal 
{ 
    private Animal() 
    { 
    } 

    public Animal(string name) 
    { 
     // ... 
    } 

    // ... 
} 


public class Penguin : Animal 
{ 
    // ... 
} 


public class Chimpanzee : Animal 
{ 
    // ... 
} 

而且我也有下面的类:

public class ZooPen<T> 
    where T : Animal 
{ 
    // ... 
} 

我想允许new ZooPen<Penguin>()new ZooPen<Chimpanzee>(),但我想禁止​​。

这可能吗?

+1

为什么你需要这个限制?它是使用通过反射得到的构造函数创建子类吗?如果是这样,为什么不添加一个运行时检查来清除*为什么*限制是存在的,而不是从所提出的黑客中产生可能令人困惑的编译时错误。 – millimoose

+0

我同意millimoose。限制对我来说很不好。如果你需要在Zoo Pen中创建新的实例,那么你可以让它将一个工厂作为构造函数的参数。 – StriplingWarrior

+0

@StriplingWarrior,我开始同意。毫无疑问,具有类型参数的类是通过反射来实例化子类的。无论如何,我正在重新考虑如何处理这个问题,所以谢谢你的建议。 – Andrew

回答

10

以下是完成您要求的一种方法。

abstract class Animal 
{ 
    readonly string Name; 
    Animal() { } 
    public Animal(string name) { Name = name; } 
} 

abstract class Animal<T> : Animal where T : Animal<T> 
{ 
    public Animal(string name) : base(name) { } 
} 

class Penguin : Animal<Penguin> 
{ 
    public Penguin() : base("Penguin") { } 
} 

class Chimpanzee : Animal<Chimpanzee> 
{ 
    public Chimpanzee() : base("Chimpanzee") { } 
} 

class ZooPen<T> where T : Animal<T> 
{ 
} 

class Example 
{ 
    void Usage() 
    { 
     var penguins = new ZooPen<Penguin>(); 
     var chimps = new ZooPen<Chimpanzee>(); 
     //this line will not compile 
     //var animals = new ZooPen<Animal>(); 
    } 
} 

任何人维护此代码可能会有点困惑,但它确实是你想要的。

+0

啊,CRTP ... – SLaks

+0

你也可以使用一个接口。 ('T:Animal,ITypedAnimal ') – SLaks

7

您可以添加new()约束,这将要求该类不是抽象的并且具有默认构造函数。

+0

谢谢,但我面临的问题是具体类没有默认的构造函数。 – Andrew

+3

@Andrew:然后CLR类型系统不能帮你。抱歉。 – SLaks

+0

@SLaks就是我所害怕的。谢谢。 – Andrew

0
public class ZooPen<T> where T : Animal 
{ 
    public ZooPen() 
    { 
     if (typeof(T).IsAbstract) 
      throw new ArgumentException(typeof(T).Name + " must be non abstract class"); 
    } 
}