2010-02-23 41 views
6

tôi đang tạo ra một lớp tùy chỉnh chung:C# Generic loại Nguyên nhân mơ hồ

class Widget< T1, T2> 
{ 
    ... 
    public bool Bar(T1 type1) 
    { 
     ... 
    } 
    public bool Bar(T2 type2) 
    { 
     ... 
    } 
    ... 
} 

Những dòng này, tất nhiên, tạo ra một lỗi gọi biên dịch mơ hồ:

Widget<int, int> Foo = new Widget<int, int>(); 
... 
Foo.Bar(5); 
... 

Có cách nào để khắc phục này ? Có một mệnh đề mà tôi có thể đặt dọc theo các dòng "where: TypeOf (T1)! = TypeOf (T2)", hoặc bất kỳ cách nào để làm cho điều này rõ ràng? Tốt hơn là int, int sẽ có sẵn, nhưng nó không phải là manditory.

Cập nhật:

Tôi thực sự tự mình khám phá ra một giải pháp có thể chấp nhận (cho tôi) cho vấn đề này, đối với những người quan tâm đến

class Widget< T1, T2> 
{ 
    ... 
    public bool Bar(object o) 
    { 
     if(o.GetType() == typeof(T1)) 
     { 
      ... 
     } 
     if(o.GetType() == typeof(T2)) 
     { 
      ... 
     } 
    } 
    ... 
} 
+0

Tôi tự hỏi trường hợp thế giới thực là gì ... – user76035

+0

trong thực tế nó trở thành và phương pháp không hợp lệ quá tải – Perpetualcoder

+1

@wwosik: Từ điển có 2 khóa. –

Trả lời

18

Is there a clause that I can put along the lines of "where : TypeOf(T1) != TypeOf(T2)"

Bạn có thể làm cho hàm tạo của bạn ném một ngoại lệ vào thời gian chạy. Nhưng không có cách nào để ngăn chặn tình trạng này tại thời gian biên dịch.

Any way to make this unambiguous?

Bạn nên thay đổi tên của các phương pháp để chúng không va chạm. Đó là điều xa nhất và an toàn nhất để làm.

Trong thực tế, IIRC CLR có quyền không tạo ra một loại tạo ra sự mơ hồ trong các chữ ký phương thức như vậy. (Rõ ràng việc thực hiện của chúng tôi thực sự thành công, nhưng bạn đang giẫm lên băng rất mỏng khi bạn kéo những loại shenanigans này.)

Làm điều này thực sự là một ý tưởng tồi vì nó có thể đưa bạn vào tất cả các loại rắc rối. Dưới đây là một ví dụ về cách mà gặp rắc rối:

http://blogs.msdn.com/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx

http://blogs.msdn.com/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx

Cũng lưu ý rằng trình biên dịch sẽ dừng bạn từ việc tạo ra một loại như vậy mà nó thực hiện hai giao diện đó có thể là giống hệt nhau đang xây dựng. Đây là bất hợp pháp:

class C<T, U> : IFoo<T>, IFoo<U> { ... } 

vì sau đó bạn có thể xây dựng C<int, int> và CLR sẽ không có cách nào để biết mà phương pháp tương ứng với đó khe cắm giao diện.

Nhưng tôi dường như đã bị phân tán một chút. Trở lại chủ đề.

Vì bạn là tác giả của lớp này, bạn có thể chọn đổi tên các phương thức "Bar" để chúng khác nhau theo bất kỳ công trình xây dựng nào có thể. Giả sử bạn bướng bỉnh chọn không. Có bất kỳ điều gì mà người dùng trong lớp không may của bạn có thể thực hiện nếu họ muốn thực hiện Widget<int, int> không? Có, thực sự, có, như kvb chỉ ra. Họ có thể xác định các phương pháp mở rộng làm điều đúng.

public static void BarTheFirst<A, B>(this Widget<A, B> w, A a) 
{ 
    w.Bar(a); 
} 

public static void BarTheFirst<A, B>(this Widget<A, B> w, B b) 
{ 
    w.Bar(b); 
} 

độ phân giải quá tải được thực hiện tại thời gian biên dịch, và tại thời gian biên dịch tất cả chúng ta đều biết là người đầu tiên gọi là Bar mà phải mất một "A", và một trong những thứ hai gọi là Bar mà phải mất một " B ". Chúng tôi không thực hiện lại độ phân giải quá tải khi chạy, do đó, bây giờ bạn có thể nói

Widget<int, int> w = whatever; 
w.BarTheFirst(5); 
w.BarTheSecond(10); 

và nó sẽ làm điều đúng.

+0

"Trong thực tế, IIRC CLR có quyền không tạo ra một loại tạo ra sự mơ hồ trong các chữ ký phương thức như vậy". Nghiêm túc? Nếu đó là trường hợp, không nên trình biên dịch C# nhổ ra một cảnh báo (ít nhất) khi bạn tạo 'Widget '? –

+0

Vâng, nó có: xem OP: "lỗi biên dịch cuộc gọi mơ hồ" – user76035

+0

@wwosik: Lỗi đó là dành cho cuộc gọi phương thức. Eric đang nói về CLR thổi lên chương trình vào thời điểm đó một loại được tạo **. Trên thực tế, khi tôi nghĩ về nó, nó không phải dễ dàng cho trình biên dịch để tìm ra rằng khi nó được lồng sâu trong các phương thức chung trong nói, các hội đồng bên ngoài. –

5

Cho chức năng của mình tên duy nhất

0

này trông giống như một trường hợp bạn sẽ muốn có một cơ sở chung lớp

abstract class WidgetBase<T1> 
{ 

    public abstract bool Bar(T1 type); 
    ... 
} 

Sau đó kế thừa để thực hiện bạn

class WidgetA : WidgetBase<int> 
{ 
    public bool Bar(int type) 
    { 
     ... 
    } 
} 

class WidgetB : WidgetBase<int> 
{ 
    public bool Bar(int type) 
    { 
     ... 
    } 
} 
1

Tôi đồng ý với những người khác rằng bạn nên thay đổi lớp học của bạn để các va chạm không xảy ra (ví dụ: bằng cách đổi tên các phương thức). Tuy nhiên, nếu bạn không sở hữu lớp, có một workaround:

public static class WidgetExtensions 
{ 
    public static bool Bar1<T1,T2>(this Widget<T1, T2> w, T1 t1) { return w.Bar(t1); } 
    public static bool Bar2<T1,T2>(this Widget<T1, T2> w, T2 t2) { return w.Bar(t2); } 
} 

Bạn có thể sử dụng các phương pháp khuyến nông để gọi Bar quá tải thích hợp. Các phương thức tĩnh không cần phải là các phương thức mở rộng, nhưng tôi nghĩ nó làm cho nó rõ ràng hơn một chút.