2010-05-27 28 views
5

Tôi có một lớp trong C# với một mẫu và phương pháp tĩnh tương tự nhưTạo Generic Class Instance từ Phương pháp tĩnh trong một lớp có nguồn gốc

class BClass<T> 
{ 
    public static BClass<T> Create() 
    { 
    return new BClass<T>(); 
    } 
} 

Từ này tôi lấy được một lớp và chỉ định một mẫu tham số để các lớp cơ sở

class DClass : BClass<int> { } 

một vấn đề xảy ra khi tôi cố gắng sử dụng các phương pháp tĩnh để tạo ra một thể hiện của D

class Program 
{ 
    static void Main(string[] args) 
    { 
    DClass d = DClass.Create(); 
    } 
} 

Cung cấp lỗi trình biên dịch "Không thể chuyển đổi hoàn toàn loại 'Test.BClass < int>' thành 'Test.DClass'."

Thêm các dẫn truyền dưới đây vào ngoại lệ truyền thời gian chạy.

DClass d = (DClass)DClass.Create(); 

Có cách nào để cho phép phương pháp tĩnh tạo ra các phiên bản của lớp dẫn xuất không? Lý tưởng nhất là tôi muốn tương đương với một C++ typedef và tôi không muốn cú pháp dưới đây (mà không làm việc).

BClass<int> d = DClass.Create(); 

Trả lời

5

Có nó có thể, bằng việc có một kiểu tham chiếu đến kiểu riêng của mình. Lưu ý rằng trong thế giới .NET chúng ta đang nói về generics, không phải là các khuôn mẫu, mà có những khác biệt quan trọng trong cách chúng hoạt động.

class BClass<T, TSelf> where TSelf: BClass<T, TSelf>, new() { 
    public static TSelf Create() { 
     return new TSelf(); 
    } 
} 

class DClass: BClass<int, DClass> {} 

class Program { 
    static void Main(string[] args) { 
     DClass d = DClass.Create(); 
    } 
} 
+0

Bạn không nghĩ rằng lớp học có thể tham chiếu chính nó như một tham số kiểu trong siêu lớp của nó? Nghịch lý gà và trứng hoặc một cái gì đó ... –

+0

Thông minh và một chút kỳ quái! ;) Những bất lợi duy nhất tôi thấy ở đây là có vẻ như không bao giờ có cách nào để khởi tạo một đồng tiền cũ 'BClass ', như trong mã ban đầu của OP. –

+0

@Peter, tôi thực sự đã sử dụng thành công điều này khá nhiều. Ví dụ, nó cũng cho phép bạn tạo một phương pháp sao chép tốt hơn vì nó loại bỏ sự cần thiết phải tái diễn,… – Lucero

7

Có vẻ như những gì bạn muốn là dành cho DClass làm bí danh cho BClass<int>. Nhưng đó không phải là những gì bạn có ở đây. Những gì bạn có là DClasscó nguồn gốc từBClass<int>. Do đó, hãy gọi DClass.Create(); tạo một số BClass<int>, là không a DClass (đó là cách khác).

Điều này có thể làm cho nó rõ ràng hơn. Giả sử bạn có hệ thống cấp bậc này:

class Rectangle { 
    static Rectangle Create() { 
     return new Rectangle(); 
    } 
} 

class Square : Rectangle { } 

// code elsewhere 
var shape = Square.Create(); // you might want this to return a square, 
          // but it's just going to return a rectangle 

Một lựa chọn để có được một cái gì đó giống như các chức năng bạn muốn có thể để xác định phương pháp Create của bạn như thế này:

static TClass Create<TClass>() where TClass : BClass<T>, new() { 
    return new TClass(); 
} 

// code elsewhere 
var shape = DClass.Create<DClass>(); 

Đó là một chút lộn xộn, mặc dù (và cũng đòi hỏi bạn viết một hàm tạo parameterless cho DClass). Nếu bạn đã chết khi sử dụng phương thức Create để khởi tạo đối tượng của mình, hãy xem xét viết một lớp nhà máy cho nó.

1
class BClass<T> 
    { 
     public static T1 Create<T1, T2>() where T1 : BClass<T2>, new() 
     { 
      return new T1(); 
     } 
    } 

    class DClass : BClass<int> { } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      DClass d = DClass.Create<DClass, int>(); 
     } 
    } 
Các vấn đề liên quan