2015-12-05 20 views
15

Tôi đang gặp một thời gian khó khăn để hiểu tại sao nó sẽ có lợi để làm một cái gì đó như thế này: (Mẫu là một lớp)Mục đích của việc hạn chế kiểu generic trong một phương thức là gì?

static void PrintResults<T>(T result) where T : Sample 

Nó sẽ không thể tốt hơn để chỉ cần vượt qua mẫu vào phương pháp này?

static void PrintResults (Sample result) 
+6

Đối với những thứ được chuyển đến phương pháp, lợi ích thực sự là khá nhỏ. Đối với những thứ được trả lại một lần nữa nó sẽ giúp nhiều hơn một chút bởi vì người tiêu dùng không cần phải đúc. – Joey

Trả lời

10

Tôi khuyên bạn nên tránh các loại chung mà cú pháp không chung chung hoạt động, chẳng hạn như ví dụ bạn đã cung cấp. Tuy nhiên, có những trường hợp hữu ích khác.

Ví dụ, xác định kiểu trả về quát:

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

// Calling code 
Sample sample = Create<Sample>(); 

thay vì

static object Create() 
{ 
    return new Sample(); 
} 

// Calling code 
Sample sample = (Sample) Create(); 

Bạn cũng có thể sử dụng các mẫu để đặt nhiều hạn chế đối với một loại. Ví dụ:

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

interface IMyInterface {} 
class MyClass : IMyInterface { } 

// Calling code. 
MyClass myClass = Create<MyClass>(); 

Điều này cho phép tạo chung một loại mới triển khai giao diện cụ thể và có một hàm tạo chung. Đồng thời:

static void DoSomething<T>(T t) where T: IMyInterface1, IMyInterface2 
{ 
    t.MethodOnIMyInterface1(); 
    t.MethodOnIMyInterface2(); 
} 

interface IMyInterface1 
{ 
    void MethodOnIMyInterface1(); 
}  
interface IMyInterface2 
{ 
    void MethodOnIMyInterface2(); 
}  
class MyClass: IMyInterface1, IMyInterface2 
{ 
    // Method implementations omitted for clarity 
} 

// Calling code 
MyClass myclass' 
DoSomething(myclass); // Note that the compiler infers the type of T. 

Nơi bạn có thể yêu cầu nhiều giao diện trên một tham số duy nhất mà không (1) tạo loại mới triển khai tất cả các giao diện này và (2) yêu cầu tham số thuộc loại đó.

Khi @dcastro chỉ ra câu trả lời của mình, các loại chung cũng có thể yêu cầu trình biên dịch yêu cầu loại là giống nhau. Ví dụ:

static void DoSomething<T>(T t1, T t2) where T: MyType 
{ 
    // ... 
} 

class MyType {} 
class MyType1: MyType {} 
class MyType2: MyType {} 

// Calling code 
MyType1 myType1; 
MyType2 myType2; 
DoSomething<MyType>(myType1, myType2); 

Trong trường hợp trình biên dịch đòi hỏi t1 và t2 là cùng loại nhưng có thể là bất kỳ loại mà được thừa hưởng MyType. Điều này rất hữu ích trong các khung kiểm thử đơn vị tự động, chẳng hạn như NUnit hoặc MSTest, để kiểm tra tính bình đẳng và so sánh chung.

+1

Các bit ở cuối về buộc các loại tương tự là không chính xác. Bất kỳ cái nào trong số này sẽ biên dịch tốt 'DoSomething (mytype1, mytype2); DoSomething ((MyType) mytype1, mytype2); '... – Brandon

+0

@akton cảm ơn câu trả lời chi tiết. Tôi thực sự đánh giá cao tất cả các câu trả lời được cung cấp! Tôi nhận ra rằng tôi đã không đưa ra ví dụ tốt nhất để làm việc nhưng bạn đã xoay xở trả lời tốt câu hỏi. Cảm ơn một lần nữa! – Anonymous

+0

@Brandon Câu hỏi không phải là liệu mọi thứ có biên dịch hay không. Các kiểu generic (1) làm cho mã dễ đọc hơn (mặc dù không phải trong trường hợp của OP) và (2) di chuyển kiểm tra nhiều hơn vào thời gian biên dịch từ thời gian chạy (thường là bằng cách thay thế phôi). Trong trường hợp cụ thể, đây không phải là ví dụ tốt nhất nhưng đủ tốt để trả lời câu hỏi của OP. – akton

2

Trong khoảng trắng, bạn có thể sử dụng giao diện để làm cho nhiều loại hoạt động, vì vậy các generics không thường hữu ích ở đây.

Chỉ ngoại lệ là những hạn chế về generics. Và do đó tôi không có nghĩa là một cái gì đó như nơi T: IA, IB vì điều này có thể được thực hiện bởi một giao diện tốt mà cả hai thực hiện IA và IB. Điều này sẽ có được mệt mỏi tại một số điểm tuy nhiên kể từ khi bạn sẽ cần nhiều hơn và nhiều hơn nữa giao diện. Vì vậy, cho phép xem xét ATH lớp "khó khăn đặc biệt" và mới

public void AddNew(List<T> items) where T : new 
{ 
    items.Add(new T()); 
} 

và lớp đó là hữu ích nếu phương pháp đột biến tham số của nó, mà không làm việc, cho struct

static void IncA<T>(T item) where T: class, IA 
{ 
    item.A++; 
} 

Sức mạnh thực sự của Generics là khi các phương thức có kiểu trả về chung hoặc các lớp chung chung như Danh sách <T>. Bạn không muốn triển khai một lớp mới cho mỗi Danh sách bạn cần.

3

Hầu hết các câu trả lời đều đưa ra các giải thích về tính hữu ích của generics liên quan đến các giao diện không thực sự có vẻ để giải quyết câu hỏi thực tế của bạn.

Sự thật là, đối với ví dụ bạn đã đăng, không có lợi ích khi sử dụng phương pháp chung. Nó thực sự là tồi tệ hơn bởi vì nó sẽ gây ra nhiều triển khai của cùng một chức năng được tạo ra và bao giờ tăng nhẹ kích thước mã khi chạy.

+1

Tôi không nghĩ rằng những gì bạn đề cập đến "nhiều triển khai" được áp dụng trong trường hợp của mình bởi vì 'Mẫu' nhất thiết là một kiểu tham chiếu (trên thực tế, anh ta nói với chúng ta đó là một' lớp '). Đối với các loại tham chiếu, không có "nhiều triển khai". Ngoài ra, bạn có thể đúng không có nhiều lợi ích trong kịch bản cụ thể của mình. Chúng ta nhận được một kiểu bổ sung 'T' (là một kiểu kiểu thời gian biên dịch' typeof (T) 'không nhất thiết phải giống với' result.GetType() '). Phương thức này có thể sử dụng kiểu đó, ví dụ 'var config = HelperClass .GetConfig();' hoặc một cái gì đó. –

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