2013-05-28 28 views
9

Có thể hạn chế tham số kiểu để triển khai thực hiện cụ thể của lớp trừu tượng không, nếu những triển khai đó không có các hàm tạo mặc định?Thêm ràng buộc tham số kiểu để ngăn các lớp trừu tượng

Ví dụ, nếu tôi có:

public abstract class Animal 
{ 
    private Animal() 
    { 
    } 

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

    // ... 
} 


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


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

Và tôi cũng có lớp sau đây:

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

Tôi muốn cho phép new ZooPen<Penguin>()new ZooPen<Chimpanzee>(), nhưng tôi muốn để không cho phép new ZooPen<Animal>().

Điều này có khả thi không?

+1

Tại sao bạn cần hạn chế này? Là nó để tạo ra các lớp con bằng cách sử dụng một constructor bạn nhận được bằng cách phản ánh? Nếu vậy, tại sao không chỉ thêm một kiểm tra thời gian chạy mà làm cho nó rõ ràng * tại sao * các hạn chế là có thay vì một lỗi biên dịch có khả năng gây nhầm lẫn thời gian từ hacks đề xuất. – millimoose

+0

Tôi đồng ý với millimoose. Các hạn chế có mùi xấu với tôi. Nếu bạn cần tạo các cá thể mới trong Bút Zoo, thì bạn có thể làm cho nó lấy một nhà máy làm đối số hàm tạo. – StriplingWarrior

+0

@StriplingWarrior, tôi bắt đầu đồng ý. millimoose đúng là lớp có tham số kiểu là instantiating các lớp con thông qua sự phản chiếu. Dù sao tôi đang suy nghĩ lại làm thế nào tôi sẽ xử lý này, vì vậy cảm ơn cho đề nghị này. – Andrew

Trả lời

10

Dưới đây là một cách để thực hiện những gì bạn đang yêu cầu.

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>(); 
    } 
} 

Bất kỳ ai duy trì mã này có thể có chút nhầm lẫn, nhưng nó thực sự chính xác như bạn muốn.

+0

Ah, CRTP ... – SLaks

+0

Bạn cũng có thể sử dụng giao diện. ('trong đó T: Động vật, ITypedAnimal ') – SLaks

7

Bạn có thể thêm ràng buộc new(), điều này sẽ yêu cầu lớp không được trừu tượng và có hàm tạo mặc định.

+0

Cảm ơn, nhưng vấn đề tôi đang phải đối mặt là các lớp cụ thể không có các hàm tạo mặc định. – Andrew

+3

@Andrew: Sau đó, hệ thống kiểu CLR không thể giúp bạn. Lấy làm tiếc. – SLaks

+0

@SLaks đó là điều tôi sợ. Cảm ơn. – 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"); 
    } 
} 
Các vấn đề liên quan