2012-03-08 31 views
5

Đó là một phần tò mò và một phần vì tôi chỉ đang cố gắng sử dụng điều này. Nếu bạn có các định nghĩa sau, điều này không được trình biên dịch cho phép vì nó nói rằng thành viên đã được định nghĩa. Lý do đằng sau không cho phép quá tải độc quyền của các thông số loại chung là gì?Không cho phép quá tải các thông số loại chung?

void Get<T>() where T: struct {} 
void Get<T>() where T: class {} 

Dường như với tôi rằng không có vấn đề cố hữu với điều này. Người ta có thể lập luận rằng nó không phải là luôn luôn rõ ràng mà trình biên dịch nên chọn trong trường hợp các định nghĩa chồng lên nhau (nhưng một độ phân giải phổ biến có vẻ là trận đấu cụ thể nhất đầu tiên).

Ai đó có thể giúp tôi hiểu hoặc chỉ ra một nguồn tài nguyên nào lý do đằng sau việc không cho phép điều này?

+0

Không quan tâm, loại trường hợp sử dụng thực tế của bạn đang cố gắng làm gì? – AakashM

+0

@AakashM: đơn giản, tôi cần chuyển đổi các kiểu nullable theo một cách khác với các kiểu giá trị không nullable. Tôi nghĩ rằng quá tải chung là một cách nhanh chóng để sửa chữa nó. Phương thức này lấy một đối tượng và một kiểu param và tôi không thể hạn chế kiểu param (tốt, tôi có thể, nhưng tôi không thể quá tải nó). – Abel

Trả lời

9

Eric Lippert đã trả lời thế này, trong một bài đăng blog trên các ràng buộc chung và phương pháp chữ ký: http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

hạn chế trên các loại generic không nằm trong chữ ký phương pháp trong CLR, do đó bạn không thể có hai phương pháp mà chỉ khác nhau về các ràng buộc kiểu chung. Nếu không có sự hỗ trợ của CLR, sẽ rất khó để có được C# hỗ trợ chúng theo một cách hợp lý tương thích với các ngôn ngữ .NET khác.

+0

Nếu bạn nói theo cách đó, có vẻ hợp lý. Người ta chỉ có thể tự hỏi, _why_ nó không phải là một phần của chữ ký phương pháp? Anders Hejlsberg có lý do chính đáng để không thiết kế nó theo bất kỳ cách nào khác không? Chưa đọc đầy đủ bài viết của Lippert. Cảm ơn con trỏ. – Abel

+1

Đoán của tôi là nó là một giới hạn CLR - CLR cũng không xem xét các ràng buộc kiểu generic một phần của chữ ký phương thức. Không có cách nào để biểu diễn các ràng buộc chung trong biểu diễn nhị phân của các chữ ký phương thức, do đó, nó là một hạn chế khá sâu. – thecoop

+4

@Abel: thecoop là chính xác; đây là một hạn chế của CLR. Tất nhiên chúng ta có thể làm cho các ràng buộc trở thành một phần của chữ ký, điều này chắc chắn sẽ hữu ích trong trường hợp cụ thể của bạn. Nhưng trong trường hợp chung, nó trình bày rất nhiều vấn đề.Ví dụ: 'void M () trong đó T: IFoo {}' và 'void M () trong đó T: IBar {}' sẽ là chữ ký phương thức khác nhau; Vậy phương thức nào là 'M ' trong đó 'Blah' là lớp thực hiện cả hai' IFoo' và 'IBar' là gì? Các quy tắc để đối phó với các chữ ký mơ hồ đã đủ phức tạp rồi; chúng ta không thêm một máy chủ hoàn toàn mới của các cách để được mơ hồ. –

1

Hạn chế struct trên Nullable<T> là IMHO thực sự không may. Một cái gì đó giống như một Nullable<String> hoặc một Nullable<Nullable<Nullable<int>>> có thể có lãng phí, nhưng vì vậy những gì? Hộp trước đây là nội dung của nó; unbox nó như là nội dung của nó và thiết lập các HasValue nếu nội dung là không null. Hãy đặt tên cũ là int nếu tất cả báo cáo không có giá trị HasValue và khi hủy hộp, hãy đặt HasValue của tất cả các mục lồng nhau nếu nội dung không phải là rỗng.

Nếu không, tôi khuyên bạn nên tạo một lớp chung tĩnh với tham số kiểu T, trong đó có thuộc tính ủy quyền chấp nhận tham số T làm tham số. Thuộc tính phải trả lại nội dung của trường riêng tư sẽ được khởi tạo để trỏ đến phương thức sẽ kiểm tra loại T và đặt đại biểu thành phiên bản struct hoặc class nếu thích hợp.

Đây là ví dụ về những gì tôi đang nói đến; điều này sử dụng các ràng buộc giao diện khác nhau hơn là ràng buộc struct/class, nhưng các nguyên tắc tương tự có thể được sử dụng một cách hiệu quả.

 
     static class _FooDispatcher<T> 
     { 
      public static Action<T> Foo = setupFoo; 

      static void doFooWithIGoodFoo<TT>(TT param) where TT : IGoodFoo 
      { 
       Console.WriteLine("Dispatching as IGoodFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference"); 
       param.Foo(); 
      } 
      static void doFooWithIOkayFoo<TT>(TT param) where TT : IOkayFoo 
      { 
       Console.WriteLine("Dispatching as IOkayFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference"); 
       param.Foo(); 
      } 
      static void doFooSomehow<TT>(TT param) 
      { 
       Console.WriteLine("Nothing exciting with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference"); 
      } 
      static void setupFoo(T param) 
      { 
       System.Reflection.MethodInfo mi; 
       if (typeof(IGoodFoo).IsAssignableFrom(typeof(T))) 
        mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIGoodFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
       else if (typeof(IOkayFoo).IsAssignableFrom(typeof(T))) 
        mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIOkayFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
       else 
        mi = typeof(_FooDispatcher<T>).GetMethod("doFooSomehow", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
       Foo = (Action<T>)(@Delegate.CreateDelegate(typeof(Action<T>), mi.MakeGenericMethod(typeof(T)))); 
       Foo(param); 
      } 
     } 
Các vấn đề liên quan