2010-02-05 29 views
7
interface IBar { void Hidden(); } 

class Foo : IBar { public void Visible() { /*...*/ } void IBar.Hidden() { /*...*/ } } 

class Program 
{ 
    static T CallHidden1<T>(T foo) where T : Foo 
    { 
     foo.Visible(); 
     ((IBar)foo).Hidden(); //Cast required 

     return foo; 
    } 

    static T CallHidden2<T>(T foo) where T : Foo, IBar 
    { 
     foo.Visible(); 
     foo.Hidden(); //OK 

     return foo; 
    } 
} 

Có sự khác biệt nào (CallHidden1 so với CallHidden2) là mã được biên dịch thực tế không? Có sự khác biệt nào khác giữa vị trí T: Foo và T: Foo, IBar (nếu Foo triển khai IBar) khi truy cập các thành viên giao diện được triển khai một cách rõ ràng không?Giao diện và ràng buộc chung chung được thực hiện rõ ràng

Trả lời

1

Có, một chút xíu, vì thứ hai chỉ định rằng giao diện phải được triển khai, có thể trở nên quan trọng nếu Foo sau đó được thay đổi để nó không thực hiện IBar.

Điều đó sẽ làm cho nó không phù hợp để được sử dụng trong CallHidden2<> trong khi vẫn có giá trị tại thời gian biên dịch cho CallHidden1<> (mà sau đó sẽ thất bại khi chạy nếu IBar không còn được thực hiện bởi Foo).

Vì vậy, nếu chúng ở trong các hội đồng riêng biệt, siêu dữ liệu khác nhau sẽ tạo sự khác biệt. Tuy nhiên, IL được thi hành sẽ khá giống nhau nếu không giống nhau.

6

Các IL tạo ra hơi khác:

L_000d: ldarg.0 
    L_000e: box !!T 
    L_0013: callvirt instance void WindowsFormsApplication1.IBar::Hidden() 

vs

L_000d: ldarga.s foo 
    L_000f: constrained !!T 
    L_0015: callvirt instance void WindowsFormsApplication1.IBar::Hidden() 

Nếu T là một loại giá trị, điều này sẽ dẫn đến foo được đóng hộp trong CallHidden1 nhưng không phải trong CallHidden2. Tuy nhiên, vì Foo là một lớp, mọi loại T có nguồn gốc từ Foo sẽ không phải là một loại giá trị và do đó hành vi sẽ giống nhau.

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