2012-04-04 34 views
7

Tôi có giải pháp không phù hợp với những gì tôi cần, nhưng tôi đang tìm kiếm giải pháp thanh lịch để thay thế.Hạn chế loại thừa kế chung trong C#

Các mã sau đây không biên dịch, nhưng đại diện cho những gì tôi muốn làm.

interface IWebService 
{ 
} 

abstract class BaseClient<T> 
{ 
} 

class SpecializedClient : BaseClient<IWebService> 
{ 
} 

class ClientHelper<T> where T : BaseClient<*> 
{ 
} 

Trường hợp T trong ClientHelper<T> là bất kỳ lớp mà kéo dài BaseClient không phụ thuộc vào loại templated thông qua vào

Giải pháp không phù hợp mà tôi tìm thấy là:

class ClientHelper<T, U> where T : BaseClient<U> {} 

Lý do này trở nên không phù hợp là tiền đề của tôi ct kết thúc với một lớp học tương tự như:

class MyClass<A, B, C, D, E, F, G> where A : MyBaseClass<B, C, D, E, F, G> 

Tất cả các cách xuống lớp cơ sở có một loại duy nhất. Đây có phải chỉ đơn giản là chi phí của việc có một cây thừa kế phức tạp của các lớp chung hoặc có cách đơn giản hơn để thực hiện điều này trong khi vẫn giữ lại các hạn chế kiểu trên các kiểu templated?

Trả lời

5

Giải pháp "không phù hợp" của bạn là giải pháp phù hợp nếu giao diện công khai của BaseClient hiển thị thông số loại chung của nó theo bất kỳ cách nào.

Vì vậy, giả sử BaseClientkhông như bạn định nghĩa nó:

abstract class BaseClient<T> 
{ 
    //Something about T here 
} 

Sau đó T là một phần của hợp đồng giao diện công cộng của BaseClient, và do đó là một phần của hợp đồng giao diện công cộng của ClientHelper (một lần nữa, giả định rằng BaseClient<U> được hiển thị thông qua giao diện của ClientHelper).

Mặt khác, chúng ta hãy giả định nó thực sự là như ví dụ của bạn đặt nó:

abstract class BaseClient<T> 
{ 
    //Nothing about T here 
} 

Trong trường hợp đó, bạn có thể làm:

interface IBaseClient 
{ 
    //Nothing about T here 
} 

abstract class BaseClient<T> : IBaseClient 
{ 
    // Whatever you like here 
} 

ClientHelper trở thành:

class ClientHelper<T> where T : IBaseClient 
{ 
} 
+0

Giao diện có thể hoạt động đối với một phần của nó vì một số lớp của tôi không hiển thị công khai 'T' chúng đơn giản sử dụng nó trong nội bộ. Tôi sẽ lấy bất kỳ đơn giản hóa nào tôi có thể nhận được vì nó bắt đầu trở nên khó sử dụng. – Foran

+0

Điều đó đơn giản hóa tất cả các trường hợp tôi có 'Class ' trong đó 'T' không bao giờ được hiển thị công khai. Đơn giản, nhưng rõ ràng là tôi không thể nhìn thấy nó. :-) Nó cắt ra khoảng một nửa các loại cần được chuyển tiếp xung quanh. – Foran

+0

Tuyệt. Mừng vì việc này giúp ích được cho bạn. Bạn cũng có thể loại bỏ một số tham số chung bổ sung nếu bạn có thể khái quát tất cả các hoạt động *** cho một 'T' đã cho (phương thức, thuộc tính, sự kiện và trường) không phụ thuộc vào kiểu vào giao diện . –

0

Một tùy chọn có vẻ là:

interface IWebService 
{ 
} 

interface IClient<out T> 
{ 
} 

abstract class BaseClient<T> : IClient<T> 
{ 
} 

class SpecializedClient : BaseClient<IWebService> 
{ 
} 

class ClientHelper<T> where T : IClient<object> 
{ 
} 

Tuy nhiên, điều này sẽ chỉ hoạt động nếu bạn BaseClient chỉ trả lại T và không bao giờ chấp nhận.