2013-07-11 32 views
25

Hãy nói rằng tôi có giao diện như thế và thực hiện cụ thểGiao diện với tham số generic vs Interface với các phương pháp chung

public interface IMyInterface<T> 
{ 
    T My(); 
} 

public class MyConcrete : IMyInterface<string> 
{ 
    public string My() 
    { 
     return string.Empty; 
    } 
} 

Vì vậy, tôi tạo thực hiện MyConcrete cho strings, tôi có thể có thêm một thực hiện cụ thể cho int. Và đó là ok. Nhưng giả sử, mà tôi muốn làm điều tương tự, nhưng với các phương pháp thông thường, vì vậy tôi có

public interface IMyInterface2 
{ 
    T My<T>(); 
} 

public class MyConcrete2 : IMyInterface2 
{ 
    public string My<string>() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Vì vậy, tôi có cùng IMyInterface2, nhưng trong đó xác định hành vi chung bằng phương pháp T My<T>(). Trong lớp bê tông của tôi, tôi muốn thực hiện hành vi My, nhưng đối với loại dữ liệu cụ thể - string. Nhưng C# không cho phép tôi làm điều đó.

Câu hỏi của tôi là tại sao tôi không thể làm điều đó? Nói cách khác, nếu tôi có thể tạo triển khai cụ thể MyInterface<T>MyClass : MyInterface<string> và dừng tính chung chung tại thời điểm này, tại sao tôi không thể thực hiện điều đó bằng phương pháp chung - T My<T>()?

+1

Bạn không thể * giảm * khả năng khi kế thừa các loại, bạn chỉ có thể thêm vào chúng. –

Trả lời

29

phương pháp thực hiện chung của bạn đã được chung chung là tốt, vì vậy nó phải là:

public class MyConcrete2 : IMyInterface2 
{ 
    public T My<T>() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Tại sao bạn không thể làm My<string>() đây? Bởi vì giao diện hợp đồng cần một phương thức, có thể được gọi với bất kỳ tham số kiểu T nào và bạn phải thực hiện hợp đồng đó.

Tại sao bạn không thể dừng tính chung chung ở thời điểm này? Bởi vì nó sẽ gây ra những tình huống như sau:

tờ khai Class:

public interface IMyInterface2 
{ 
    T My<T>(t value); 
} 

public class MyClass21 : IMyInterface2 
{ 
    public string My<string>(string value) { return value; } 
} 

public class MyClass22 : IMyInterface2 
{ 
    public int My<int>(int value) { return value; } 
} 

Cách sử dụng:

var item1 = new MyClass21(); 
var item2 = new MyClass22(); 

// they both implement IMyInterface2, so we can put them into list 
var list = new List<IMyInterface2>(); 
list.Add(item1); 
list.Add(item2); 

// iterate the list and call My method 
foreach(IMyInterface2 item in list) 
{ 
    // item is IMyInterface2, so we have My<T>() method. Choose T to be int and call with value 2: 
    item.My<int>(2); 

    // how would it work with item1, which has My<string> implemented? 
} 
+1

Nó cần phải được công khai 'T My ()' –

+0

nếu tôi có thể tạo thực thi cụ thể MyInterface như MyClass: MyInterface và dừng genericness tại thời điểm này, tại sao tôi không thể làm điều đó với phương pháp chung - T My ()? –

+1

@JevgenijNekrasov Kiểm tra cập nhật của tôi. Tôi đã cho thấy một tình huống khi triển khai 'My ' của bạn sẽ thất bại. – MarcinJuraszek

0

Bởi vì giao diện của bạn tuyên bố một phương pháp chung T My<T>(), nhưng bạn thực hiện không thực hiện một hàm với chữ ký cụ thể đó.

Để đạt được những gì bạn muốn, bạn cần cung cấp các thông số chung T để giao diện thay vào đó, trong ví dụ đầu tiên của bạn:

public interface IMyInterface2<T> 
{ 
     T My(); 
} 

public class MyConcrete2 : IMyInterface2<string> 
{ 
    public string My() 
    { 
     throw new NotImplementedException(); 
    } 
} 
+0

Tôi biết làm thế nào để đạt được những gì tôi muốn, tôi muốn biết tại sao tôi không thể ngăn chặn tính chung chung như tôi có thể làm với giao diện –

2

khi bạn viết Phương pháp Generic Định nghĩa là để giữ cho các placeholder. Loại thực tế xuất hiện khi bạn gọi phương thức. thay vào đó, bạn nên viết

public T My<T>() 
{ 
    throw new NotImplementedException(); 
} 

và khi bạn gọi phương thức, bạn có thể sử dụng chuỗi ở đó.

+0

Tôi muốn ngăn chặn sự rộng lượng như tôi có thể làm với giao diện chung, ví dụ: MyClass: MyInterface

0

Giải pháp của bạn không hoạt động vì hai lý do.

Đầu tiên, giao diện là hợp đồng. Khi bạn triển khai IMyInterface2, bạn đảm bảo rằng bạn sẽ triển khai hàm có tên My có tham số loại chung và trả về loại đó. MyConcrete2 không làm điều này.

Thứ hai, C# generics không cho phép bất kỳ loại chuyên môn tham số kiểu nào. (Tôi muốn C# hỗ trợ điều này.) Đây là một điều phổ biến trong các mẫu C++ trong đó ví dụ của bạn sẽ biên dịch, nhưng bất kỳ tập quán nào của MyConcrete2 sẽ không biên dịch được nếu chúng không gọi My với string.

Các vấn đề liên quan