2010-11-01 55 views
28

Tôi đã đọc một bài viết tuyệt vời về MSDN liên quan đến Generics in C#.Tại sao sử dụng các ràng buộc chung trong C#

Câu hỏi xuất hiện trong đầu tôi là - tại sao tôi nên sử dụng các ràng buộc chung?

Ví dụ, nếu tôi sử dụng mã như thế này:

public class MyClass<T> where T : ISomething 
{ 
} 

tôi không thể chuyển đổi tất cả tài liệu tham khảo của T trong lớp này với ISomething?

Lợi ích của việc sử dụng phương pháp này là gì?

+0

http://msdn.microsoft.com/en-us/library/d5x73970.aspx – zebrabox

Trả lời

47

Bạn hỏi, "tôi không thể chuyển TẤT CẢ các tham chiếu của T trong lớp học này bằng ISomething?" Vì vậy, tôi nghĩ bạn có nghĩa là để so sánh:

public class MyClass<T> where T : ISomething 
{ 
    public T MyProperty { get; set; } 
} 

Với:

public class MyClass 
{ 
    public ISomething MyProperty { get; set; } 
} 

Trong ví dụ thứ hai, MyProperty chỉ đảm bảo được một thể hiện của ISomething. Trong ví dụ đầu tiên, MyProperty là bất cứ điều gì T là, ngay cả khi đó là loại phụ cụ thể của ISomething. Hãy xem xét một thực hiện cụ thể của ISomething:

public class MySomething : ISomething 
{ 
    public string MyOtherProperty { get; set; } 
} 

Bây giờ, nếu chúng ta sử dụng đầu tiên, chung chung, ví dụ, chúng ta có thể có:

MyClass<MySomething> myClass = new MyClass<MySomething>(); 
Console.WriteLine(myClass.MyProperty.MyOtherProperty); 

Mặt khác, nếu chúng ta sử dụng ví dụ thứ hai, chúng tôi sẽ không thể truy cập vào MyOtherProperty vì nó chỉ được biết đến là một ISomething:

MyClass myClass = new MyClass(); 
Console.WriteLine(myClass.MyProperty.MyOtherProperty); // Won't compile, no property "MyOtherProperty" 

Trên một lưu ý khác nhau, lý do những khó khăn kiểu này rất hữu ích là bạn có thể tham khảo MyProperty (loại T) và truy cập các thành viên của ISomething. Nói cách khác, nếu ISomething được khai báo như:

public interface ISomething 
{ 
    public string SomeProperty { get; set; } 
} 

Sau đó, bạn có thể truy cập MyProperty.SomeProperty. Nếu bạn bỏ qua số where T : ISomething thì bạn sẽ không thể truy cập SomeProperty từ T sẽ chỉ được biết là loại object.

2

Để bắt đầu, bạn có thể gọi các phương thức được xác định trong ISomething bên trong mã cho phương pháp/phương pháp chung trên lớp chung. Nếu T được phép là bất kỳ loại nào thì điều này sẽ không thể thực hiện được (mặc dù bạn luôn có thể thực hiện một số phép chạy thời gian). Vì vậy, nó cho phép bạn thực thi các ràng buộc thời gian biên dịch về những gì T có thể và do đó dựa vào những ràng buộc này khi bạn viết các lỗi thời gian chạy mã chuyển thành các lỗi biên dịch thời gian.

7

Gõ an toàn. Ví dụ: giả sử bạn đang tạo vùng chứa. Bạn có thể chuyển một thứ gì đó vào thùng chứa đó và lấy nó theo đúng mẫu mà không cần phải thực hiện bất kỳ phôi nào sau này bằng cách tham số hóa vùng chứa. Bạn chỉ đơn giản là xác định các ràng buộc về các loại thứ mà bạn sẵn sàng lưu trữ trong vùng chứa của mình.

4

Dưới đây là một ví dụ về sự khác biệt, bởi chỉ sử dụng List<>

Danh sách hình ảnh sẽ không được chung chung nhưng nó sẽ chỉ cần sử dụng IListElement ở khắp mọi nơi nó được sử dụng các generic thay thế. Bây giờ hãy tưởng tượng bạn có một vật thể như thế này.

class Element : IListElement 
{ 
    public string Something { get; set; } 
} 

bây giờ tôi chỉ có thể làm list.Add(element); và sẽ không có một sự khác biệt với một thực List<Element>. Tuy nhiên khi tôi truy xuất dữ liệu thì đó là một câu chuyện khác, nếu tôi sử dụng danh sách sử dụng IListElement thì tôi phải truyền dữ liệu của mình trở lại để tôi có thể nhận được Something trong số đó. Vì vậy tôi sẽ phải làm:

string s = ((Element)list[0]).Something; 

trong khi với chung tôi chỉ có thể làm:

string s = list[0].Something; 

tiết kiệm rất nhiều rắc rối, ofcourse nó đi một chút xa hơn đó nhưng tôi nghĩ bạn có thể lấy ý tưởng từ điều này.

1

Có, bạn có thể sử dụng ISomething thay cho T, nhưng điều đó sẽ tự đóng loại chung cho một lớp thông thường. Nó sẽ không là một loại chung nữa. Bằng cách sử dụng T, bạn giữ loại mở vào bao nhiêu loại phụ ISome tùy ý. Tái sử dụng mã mà không ảnh hưởng đến an toàn loại là lợi ích chính ở đây. Ví dụ, nếu bạn sử dụng một chồng của ISomethings, bạn có thể đẩy bất kỳ ISomething vào ngăn xếp nhưng một cửa sổ pop phải xảy ra với một downcast để subtype thực tế của ISomething cho nó là hữu ích. Downcasting tạo ra một điểm thất bại tiềm ẩn, sẽ không có điểm chung trong số Stack<T> trong đó T: ISomething

0

Người tiêu dùng của lớp học của bạn có được lợi ích về an toàn kiểu tăng lên, trong số những người khác.

class Widget : IPokable { } 

// No generics 
Widget w = (Widget)list[0]; // cast can fail 

// With generics 
Widget w = list[0]; 

Nếu không có Generics, nếu danh sách đã chứa IPokable đối tượng, dàn diễn viên vẫn còn cần thiết.

Lớp bạn đang triển khai được lợi ích của việc sử dụng các phương pháp cụ thể trên đối tượng chung.

class PokableList<T> where T : IPokable { 
    public T PokeAndGet() { 
     currentObj.Poke(); 
     return currentObj; 
    } 
} 
0

Video youtube này thực sự chứng tỏ tầm quan trọng của các ràng buộc chung chung https://www.youtube.com/watch?v=GlqBRIgMgho.

Bây giờ bên dưới có một câu trả lời văn bản dài.

“Chung giúp phân tách logic từ kiểu dữ liệu. Để chúng tôi đính kèm bất kỳ loại dữ liệu nào với bất kỳ logic nào cho khả năng sử dụng lại cao. ”

Nhưng nhiều lần một số logic có thể được gắn vào chỉ các loại dữ liệu cụ thể.

public class CompareNumeric<UNNKOWDATATYPE> 
{ 
     public bool Compareme(UNNKOWDATATYPE v1, UNNKOWDATATYPE v2) 
     { 
      if (v1 > v2) 
      {return true;} 
      else 
      {return false;} 
     } 
} 

Ví dụ ở trên là một lớp chung chung đơn giản so sánh nếu một số lớn hơn số khác. Bây giờ, so sánh lớn hơn và ít hơn là rất cụ thể đối với các kiểu dữ liệu số. Những loại so sánh này không thể được thực hiện trên các loại không phải dạng số như chuỗi.

Vì vậy, nếu một số sử dụng các lớp có loại “int” hoàn toàn hợp lệ.

CompareNumeric<int> obj = new CompareNumeric<int>(); 
bool boolgreater = obj.Compare(10,20); 

Nếu ai đó sử dụng nó với kiểu dữ liệu "đôi" lại hoàn toàn hợp lệ.

CompareNumeric<double> obj = new CompareNumeric<double>(); 
bool boolgreater = obj.Compare(100.23,20.45); 

Nhưng việc sử dụng loại dữ liệu chuỗi với logic này sẽ dẫn đến kết quả không mong muốn. Vì vậy, chúng tôi muốn hạn chế hoặc đặt một ràng buộc về loại có thể được gắn vào một lớp chung chung này đạt được bằng cách sử dụng "ràng buộc chung".

CompareNumeric<string> obj = new CompareNumeric<string>(); 
bool boolgreater = obj.Compare(“interview”,”interviewer”); 

Loại chung có thể bị hạn chế bằng cách chỉ định loại dữ liệu bằng từ khóa "WHERE" sau lớp chung như được hiển thị trong mã bên dưới. Bây giờ nếu bất kỳ khách hàng nào cố gắng đính kèm kiểu dữ liệu “chuỗi” với lớp bên dưới nó sẽ không cho phép, do đó tránh các kết quả không mong muốn.

public class CompareNumeric<UNNKOWDATATYPE> where UNNKOWDATATYPE : int, double 
{ 

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