2012-12-19 23 views
11

Hãy ví dụ này:Trong C#, tại sao việc triển khai giao diện phải thực hiện một phiên bản khác của phương thức một cách rõ ràng?

public interface IFoo 
{ 
    IFoo Bar(); 
} 

public class Foo : IFoo 
{ 
    public Foo Bar() 
    { 
     //... 
    } 

    IFoo IFoo.Bar() { return Bar(); } //Why is this necessary? 
} 

Tại sao là việc thực hiện ngầm của IFoo Bar() cần thiết mặc dù Foo chuyển đổi để IFoo mà không có một diễn viên?

+0

Tại sao bạn lại làm điều này? Bạn có hiệu quả buộc người dùng của 'Foo' vào việc thực hiện cụ thể, làm cho chế nhạo cho các bài kiểm tra đơn vị khó khăn, và nói chung tăng khớp nối trong ứng dụng của bạn ... –

+0

Hai cách tiếp cận là khá nhiều độc quyền. Cả hai đều có tác dụng nhưng có mục đích khác nhau. Bạn sẽ không sử dụng cả hai cách tiếp cận cho cùng một giao diện trong cùng một lớp cụ thể (ít nhất là không phải là tôi có thể nghĩ đến) – dkackman

+0

@SteveCzetty Do đó câu hỏi của OP; nơi thực hiện một cách rõ ràng giao diện là cần thiết. –

Trả lời

4

Bạn có thể giải quyết nó như thế này (một chút xấu xí, nhưng sẽ chăm sóc của các gõ mạnh):

public interface IFoo<T> where T : IFoo<T> 
{ 
    T Bar(); 
} 

public class Foo : IFoo<Foo> 
{ 
    public Foo Bar() 
    { 
     //... 
    } 
} 
+1

Большое спасибо, תודה רבה! – Matt

+0

Điều này không biên dịch vì không có giao diện 'IFoo' không chung chung. –

+0

Bạn nói đúng, tôi đã chỉnh sửa mã. –

3

Bởi vì bạn không phải lúc nào cũng muốn phương pháp triển khai giao diện hoạt động giống như một phiên bản khác của phương thức có cùng chữ ký.

Bạn cũng có thể muốn một lớp để triển khai phương thức cho giao diện nhưng không thể truy cập phương thức đó từ một thể hiện của chính lớp đó.

5

Microsoft có một số detailed write up về chủ đề này nhưng nó sẽ tóm tắt việc triển khai nhiều giao diện/lớp học có cùng phương pháp trong đó. Ngụ ý không còn hoạt động trong ngữ cảnh đó.

class Test 
{ 
    static void Main() 
    { 
     SampleClass sc = new SampleClass(); 
     IControl ctrl = (IControl)sc; 
     ISurface srfc = (ISurface)sc; 

     // The following lines all call the same method. 
     sc.Paint(); 
     ctrl.Paint(); 
     srfc.Paint(); 
    } 
} 


interface IControl 
{ 
    void Paint(); 
} 
interface ISurface 
{ 
    void Paint(); 
} 
class SampleClass : IControl, ISurface 
{ 
    // Both ISurface.Paint and IControl.Paint call this method. 
    public void Paint() 
    { 
     Console.WriteLine("Paint method in SampleClass"); 
    } 
} 

// Output: 
// Paint method in SampleClass 
// Paint method in SampleClass 
// Paint method in SampleClass 

Nếu chúng tôi có cách tiếp cận rõ ràng, chúng tôi sẽ kết thúc với điều này.

public class SampleClass : IControl, ISurface 
{ 
    void IControl.Paint() 
    { 
     System.Console.WriteLine("IControl.Paint"); 
    } 
    void ISurface.Paint() 
    { 
     System.Console.WriteLine("ISurface.Paint"); 
    } 
} 

Tất cả đều được cung cấp để cung cấp tính duy nhất khi các loại thực hiện xung đột. Trong ví dụ của bạn, FooIFoo.

+0

Vâng nhưng chỉ có một giao diện ở đây. – Matt

+0

Điều này không trả lời câu hỏi về loại trả về. –

+0

@Matt Điều chỉnh hơi dài một chút, để lưu ý rằng một giao diện duy nhất đang được phát nhưng lớp đó cũng thực hiện chữ ký phương thức đó. –

5

Nó cần thiết trong trường hợp này vì C# không hỗ trợ kiểu trả co-sai cho các giao diện, vì vậy chức năng của bạn

public Foo Bar() 
{ 
    //... 
} 

không đáp ứng các giao diện IFoo kể từ khi kiểu trả về của phương pháp Bar là khác nhau.

Vì bạn cũng muốn triển khai giao diện, lựa chọn duy nhất của bạn là làm như vậy một cách rõ ràng vì bạn đã có phương thức Bar() được xác định trên lớp.

+0

Có, nhưng ** tại sao ** không C# cho phép điều này? –

+2

@IlyaKogan - Tôi không biết tại sao C# không hỗ trợ hiệp phương sai kiểu trả về - bạn phải hỏi các nhà thiết kế. C# thường thích rằng mọi thứ được làm rõ ràng, vì vậy nó có thể ngăn chặn các giao diện vô tình được triển khai thực hiện. – Lee

+1

@IlyaKogan Điều này trả về mọi câu hỏi về _why_ liên quan đến việc thực hiện; bởi vì họ đã chọn. –

0

Tôi khuyên bạn nên duy trì triển khai ngầm định như được bảo vệ thay vì công khai.

public class Foo : IFoo 
{ 
    **protected virtual** Foo Bar() 
    { 
     //... 
    } 

    IFoo IFoo.Bar() { return Bar(); } 
} 

có một câu trả lời khá rộng rãi cho lý do tại sao/khi nào sử dụng thực hiện rõ ràng trong luồng này:

implicit vs explicit interface implementation

Một lý do chính đáng cho việc sử dụng thực hiện rõ ràng là bạn có thể dễ dàng sử dụng dependency injection để có một khớp nối lỏng lẻo hơn khi bạn sử dụng lớp Foo của bạn.

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