2011-07-19 63 views
14
public abstract class EntityBase { ... } 

public interface IFoobar 
{ 
    void Foo<T>(int x) 
     where T : EntityBase, new(); 
} 

public interface IFoobar<T> 
    where T : EntityBase, new() 
{ 
    void Foo(int x); 
} 

public class Foobar<T> : IFoobar, IFoobar<T> 
    where T : EntityBase, new() 
{ 
    public void Foo(int x) { ... } 

    void IFoobar.Foo<T>(int x) { Foo(x); } 
} 

tôi nhận được một cảnh báo trình biên dịch: Type parameter 'T' has the same name as the type parameter from outer type '...'Loại tham số 'T' có cùng tên với tham số kiểu từ loại ngoài '...'

tôi đã cố gắng thực hiện: void IFoobar.Foo<U>(int x) { Foo(x); }, tuy nhiên sau đó tôi không thể đảm bảo rằng U và T là như nhau. Cách mà lớp Foobar được triển khai, điều rất quan trọng là chúng giống nhau.

Tôi cũng đã thử: void IFoobar.Foo<U>(int x) where U : T { Foo(x); }, tuy nhiên điều đó không đảm bảo rằng U và T bằng nhau và nó không cho phép tôi xác định lại ràng buộc vì nó đã được xác định trên giao diện.

+0

Bạn đang cố gắng làm gì? Tại sao bạn định nghĩa lại T nếu nó được chỉ định trong lớp? Nếu bạn có nhu cầu xác định nó thì nó phải tách biệt nếu không T đã được lớp đó chỉ rõ. Nếu bạn muốn giải quyết điều này, hãy đặt T trên giao diện nếu bạn có thể. Đó là những gì tôi đã làm khi tôi thấy mình sao chép thông số kỹ thuật loại. –

Trả lời

8

bạn có thể làm một trong hai điều:

  1. Bỏ qua các cảnh báo và làm cho cả hai loại T.
  2. Làm một kiểm tra thời gian chạy và ném một ngoại lệ:

    if (typeof(T) != typeof(U)) throw Exception("Not the same type"); 
    

Như những người khác đã nói, có lẽ bạn cần phải suy nghĩ lại về cách bạn đang có thiết kế giao diện của bạn.

3

Chỉ cần cố gắng

void IFoobar.Foo<U>(int x) { Foo(x); } 

Tất nhiên, điều đó vẫn không đảm bảo rằng U cũng giống như T. Bạn không thể thực thi tại thời điểm biên dịch, vì khi bạn triển khai giao diện, bạn phải tuân theo các quy tắc của nó - và IFoobar không hạn chế số Foo<T> và nếu bạn làm như vậy, bạn sẽ không còn triển khai giao diện nữa (theo định nghĩa, vì bạn đang nghiêm ngặt hơn, nhưng bạn đang tuyên bố rằng bạn không có).

Bạn có thể thử kiểm tra nó trong thời gian chạy thay thế, mặc dù đó là phần "gian lận" (vì bạn không thực sự tuân theo giao diện sau đó).

+0

Trong khi đó duy trì ràng buộc trên loại, nó không đảm bảo rằng 'T' và' U' là như nhau. –

+0

Điều đó không đảm bảo rằng U bằng T, và tôi không thể xác định lại các ràng buộc trên U vì chúng đã được định nghĩa trong giao diện. – michael

+0

Điều này sẽ không biên dịch. 'Các ràng buộc để ghi đè và các phương thức thực hiện giao diện rõ ràng được kế thừa từ phương thức cơ sở, vì vậy chúng không thể được chỉ định trực tiếp'. Loại bỏ mệnh đề where để sửa lỗi này. –

12

Vấn đề lớn nhất là giao diện của bạn không được xác định rõ ràng và không phù hợp với ý định mã của bạn.

Nếu T của bạn không hiển thị công khai trên giao diện, thì mã bên ngoài thậm chí không cần phải biết có T. Bạn cần phải thực hiện các phương thức nhận hoặc trả lại T hoặc có một số thuộc tính loại T hoặc bạn chỉ cần loại bỏ hoàn toàn T hoàn toàn và làm cho giao diện của bạn không chung chung.

Khi bạn cập nhật điều này, sẽ rõ ràng hơn lý do tại sao bạn không cần hai giao diện khác nhau ở đây và bạn không còn cần phải điều chỉnh chúng.

Nếu nó quay ra rằng bạn làm cần một phiên bản mà sẽ đưa T, và một phiên bản không-T, sau đó cách thành ngữ hơn để làm điều này là vượt qua xung quanh object thay vì T:

public interface IFoo 
{ 
    void DoSomething(object o); 
    object DoSomethingElse(); 
} 

public interface IFoo<T> 
{ 
    void DoSomething(T item); 
    T DoSomethingElse(); 
} 

Xem các giao diện như IEnumerable, ICollection, IList, v.v. để biết ví dụ về điều này.

Nhưng hãy cân nhắc cẩn thận. Điều này thiết kế thỏa hiệp cuối cùng (có cả một phiên bản chung và đối tượng) luôn luôn để lại một cái gì đó để được mong muốn.

Bạn sẽ hy sinh một trong các:

  • thiết kế giao diện tốt mà trực tiếp giao kết hợp đồng thiết kế (Nếu bạn ném ngoại lệ hoặc làm một không-op khi gõ sai được thông qua năm)
  • Loại an toàn, và giảm lỗi mà đi với nó (nếu bạn hoạt động một cách chính xác trên bất kỳ tuổi-object)
Các vấn đề liên quan