2012-05-31 35 views
88

Đọc this, tôi đã học được rằng có thể cho phép một phương thức chấp nhận các tham số của nhiều loại bằng cách biến nó thành một phương thức chung. Trong ví dụ này, đoạn mã sau được sử dụng với ràng buộc kiểu để đảm bảo "U" là IEnumerable<T>.Ràng buộc loại nhiều phương thức chung (OR)

public T DoSomething<U, T>(U arg) where U : IEnumerable<T> 
{ 
    return arg.First(); 
} 

tôi thấy một số mã khác mà cho phép thêm nhiều trở ngại loại, chẳng hạn như:

public void test<T>(string a, T arg) where T: ParentClass, ChildClass 
{ 
    //do something 
} 

Tuy nhiên, mã này xuất hiện để thực thi mà arg phải vừa một loại ParentClassChildClass. Những gì tôi muốn làm là nói arg mà có thể là một loại ParentClasshayChildClass theo cách sau đây:

public void test<T>(string a, T arg) where T: string OR Exception 
{ 
//do something 
} 

sự giúp đỡ của bạn được đánh giá cao như mọi khi!

+3

Bạn có thể làm gì một cách hữu ích, * theo cách chung chung * trong cơ thể của phương thức như vậy (trừ khi có nhiều kiểu xuất phát từ một lớp cơ sở cụ thể, trong trường hợp này không khai báo là ràng buộc kiểu)? –

+0

@Damien_The_Unbeliever Bạn không chắc chắn ý mình là gì trong cơ thể? Trừ khi bạn có nghĩa là cho phép bất kỳ loại nào và kiểm tra thủ công trong nội dung ... và trong mã thực tế tôi muốn viết (đoạn mã cuối), tôi muốn có thể vượt qua chuỗi HOẶC ngoại lệ, vì vậy không có lớp học mối quan hệ ở đó (ngoại trừ system.object tôi tưởng tượng). – Mansfield

+1

Cũng lưu ý rằng không sử dụng bằng văn bản 'trong đó T: chuỗi', vì' chuỗi' là một lớp ** được đóng dấu **. Điều hữu ích duy nhất bạn có thể làm là xác định tình trạng quá tải cho 'string' và' T: Exception', như được giải thích bởi @ Botz3000 trong câu trả lời của mình bên dưới. –

Trả lời

44

Điều đó là không thể. Tuy nhiên, bạn có thể xác định tình trạng quá tải cho các loại cụ thể:

public void test(string a, string arg); 
public void test(string a, Exception arg); 

Nếu chúng là một phần của lớp chung, chúng sẽ được ưu tiên hơn phiên bản chung của phương pháp.

+1

Thú vị. Điều này đã xảy ra với tôi, nhưng tôi nghĩ rằng nó có thể làm cho mã sạch hơn để sử dụng một chức năng. Ah tốt, cảm ơn rất nhiều! Chỉ cần ra khỏi tò mò, bạn có biết nếu có một lý do cụ thể điều này là không thể? (nó đã bị bỏ quên khỏi ngôn ngữ một cách có chủ ý?) – Mansfield

+2

@Mansfield Tôi không biết lý do chính xác, nhưng tôi nghĩ bạn sẽ không thể sử dụng các thông số chung theo cách có ý nghĩa nữa. Bên trong lớp học, họ sẽ phải đối xử như đối tượng nếu họ được phép có các loại hoàn toàn khác nhau. Điều đó có nghĩa là bạn cũng có thể bỏ qua tham số chung và cung cấp quá tải. – Botz3000

+2

@Mansfield, đó là vì một mối quan hệ 'hoặc' làm cho mọi việc xa đến mức hữu ích. Bạn sẽ * có * để làm phản ánh để tìm ra những gì để làm và tất cả những điều đó. (KINH QUÁ!). – Crisfole

5

Nếu ChildClass có nghĩa là nó có nguồn gốc từ ParentClass, bạn chỉ có thể viết như sau để chấp nhận cả ParentClass và ChildClass;

public void test<T>(string a, T arg) where T: ParentClass 
{ 
    //do something 
} 

Mặt khác, nếu bạn muốn sử dụng hai loại khác nhau không có quan hệ thừa kế, bạn nên xem xét các loại triển khai cùng một giao diện;

public interface ICommonInterface 
{ 
    string SomeCommonProperty { get; set; } 
} 

public class AA : ICommonInterface 
{ 
    public string SomeCommonProperty 
    { 
     get;set; 
    } 
} 

public class BB : ICommonInterface 
{ 
    public string SomeCommonProperty 
    { 
     get; 
     set; 
    } 
} 

thì bạn có thể viết hàm chung của mình;

public void Test<T>(string a, T arg) where T : ICommonInterface 
{ 
    //do something 
} 
+0

Ý tưởng hay, ngoại trừ tôi không nghĩ mình có thể làm điều này vì tôi muốn sử dụng chuỗi đó là một lớp kín theo bình luận ở trên ... – Mansfield

+0

đây là một vấn đề thiết kế trên thực tế. một hàm chung được sử dụng để thực hiện các hoạt động tương tự với việc tái sử dụng mã. cả hai nếu bạn đang có kế hoạch để làm các hoạt động khác nhau trong cơ thể phương pháp, các phương pháp tách là một cách tốt hơn (IMHO). – daryal

+0

Điều tôi đang làm là viết một hàm ghi lỗi đơn giản. Tôi muốn tham số cuối cùng đó là chuỗi thông tin về lỗi hoặc ngoại lệ, trong trường hợp đó, tôi lưu e.message + e.stacktrace thành chuỗi. – Mansfield

18

Botz Câu trả lời là chính xác 100%, đây là một giải thích ngắn gọn:

Khi bạn đang viết một phương pháp (generic hay không) và tuyên bố loại các thông số mà phương pháp này sẽ đưa bạn được xác định một hợp đồng :

Nếu bạn cho tôi một đối tượng mà biết làm thế nào để thực hiện bộ điều loại T biết làm thế nào để tôi có thể cung cấp hoặc 'a': một giá trị trả về của các loại tôi tuyên bố, hoặc ' b ': một số loại hành vi sử dụng loại đó.

Nếu bạn cố gắng và cung cấp cho nó nhiều hơn một loại tại một thời điểm (bằng cách có một hoặc) hoặc cố gắng làm cho nó trả về một giá trị có thể có nhiều hơn một loại hợp đồng mà được mờ:

Nếu bạn cho tôi một đối tượng biết cách nhảy dây hoặc biết cách tính pi đến chữ số thứ 15, tôi sẽ trả về một đối tượng có thể đi câu hoặc có thể trộn bê tông.

Vấn đề là khi bạn tham gia vào phương pháp bạn không có ý tưởng nếu họ đã cung cấp cho bạn IJumpRope hoặc PiFactory. Hơn nữa, khi bạn tiếp tục và sử dụng phương pháp (giả sử rằng bạn đã nhận được nó để biên dịch kỳ diệu) bạn không thực sự chắc chắn nếu bạn có một Fisher hoặc một AbstractConcreteMixer. Về cơ bản nó làm cho toàn bộ cách điều khó hiểu hơn.

Giải pháp cho vấn đề của bạn là một trong hai possiblities:

  1. Xác định nhiều hơn một phương pháp xác định mỗi chuyển đổi có thể, hành vi, hoặc bất cứ điều gì. Đó là câu trả lời của Botz. Trong thế giới lập trình, điều này được gọi là quá tải phương pháp.

  2. Xác định lớp cơ sở hoặc giao diện biết cách thực hiện tất cả những thứ bạn cần cho phương pháp và có một phương pháp lấy chỉ loại đó. Điều này có thể bao gồm việc đóng gói stringException trong một lớp học nhỏ để xác định cách bạn lập kế hoạch ánh xạ chúng cho việc triển khai, nhưng sau đó mọi thứ siêu rõ ràng và dễ đọc. Tôi có thể đến, bốn năm kể từ bây giờ và đọc mã của bạn và dễ dàng hiểu những gì đang xảy ra.

Bạn chọn tùy thuộc vào mức độ phức tạp của lựa chọn 1 và 2 và mức độ cần thiết.

Vì vậy, đối với tình hình cụ thể của bạn tôi sẽ tưởng tượng bạn chỉ cần kéo ra một tin nhắn hoặc một cái gì đó từ ngoại lệ:

public interface IHasMessage 
{ 
    string GetMessage(); 
} 

public void test(string a, IHasMessage arg) 
{ 
    //Use message 
} 

Bây giờ tất cả bạn cần là phương pháp mà biến đổi một string và một Exception để một IHasMessage. Rất dễ.

+0

xin lỗi @ Botz3000, chỉ cần nhận thấy tôi đã viết sai chính tả tên của bạn. – Crisfole

+0

Hoặc trình biên dịch có thể đe dọa kiểu như kiểu công đoàn trong hàm và có giá trị trả về bằng cùng loại mà nó nhận được. TypeScript thực hiện điều này. – Alex

+0

@ Alex nhưng đó không phải là những gì C# làm. – Crisfole

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