2009-02-13 40 views
5

Tôi đã kết thúc với một cái gì đó giống như mã sau trong một dự án tôi đang làm việc trên. Tôi nghĩ thật kỳ lạ khi tôi được phép làm điều đó, nhưng bây giờ tôi bắt đầu tự hỏi điều gì có thể là một kiến ​​trúc sư trên phần của tôi đã dẫn tôi đến điều này.Tính đa hình giao diện kỳ ​​lạ bằng cách sử dụng thành phần giao diện

Câu hỏi của tôi cho bạn là:

  • gì chính xác là điều này được gọi là?
  • Một số công dụng thực tế của việc này là gì?
  • Tại sao mọi người lại muốn làm điều này?

Dưới đây là giao diện của tôi:

namespace ThisAndThat 
{ 
    public interface ICanDoThis 
    { 
     string Do(); 
    } 

    public interface ICanDoThat 
    { 
     string Do(); 
    } 

    public interface ICanDoThisAndThat : ICanDoThis, ICanDoThat 
    { 
     new string Do(); 
    } 
} 

Đây là lớp bê tông của tôi:

namespace ThisAndThat 
{ 
    public class CanDoThisAndThat : ICanDoThisAndThat 
    { 
     public string Do() 
     { 
      return "I Can Do This And That!"; 
     } 

     string ICanDoThis.Do() 
     { 
      return "I Can Do This!"; 
     } 

     string ICanDoThat.Do() 
     { 
      return "I Can Do That!"; 
     } 
    } 
} 

Và qua tôi kiểm tra:

using Xunit; 

namespace ThisAndThat.Tests 
{ 
    public class ThisAndThatTests 
    { 
     [Fact] 
     public void I_Can_Do_This_And_That() 
     { 
      ICanDoThisAndThat sut = new CanDoThisAndThat(); 

      Assert.Equal("I Can Do This And That!", sut.Do()); 
     } 

     [Fact] 
     public void I_Can_Do_This() 
     { 
      ICanDoThis sut = new CanDoThisAndThat(); 

      Assert.Equal("I Can Do This!", sut.Do()); 
     } 

     [Fact] 
     public void I_Can_Do_That() 
     { 
      ICanDoThat sut = new CanDoThisAndThat(); 

      Assert.Equal("I Can Do That!", sut.Do()); 
     } 

    } 
} 

Trả lời

5

Hoàn toàn không có gì sai với mã này (miễn là nó không gây nhầm lẫn cho người dùng của bạn), và nó không phải là một mẫu với bất kỳ tên nào mà tôi quen thuộc. CanDoThisAndThat triển khai hai giao diện, vì vậy khách hàng có thể sử dụng nó theo một trong hai cách.

.NET cho phép các giao diện được triển khai theo cách này - được gọi là triển khai giao diện rõ ràng.

giao diện rõ ràng thực hiện rất hữu ích khi:

  1. Hai giao diện có định nghĩa thành viên cùng
  2. Bạn cần phải thực hiện một giao diện nhưng không muốn công bố rằng một thành viên đặc biệt là có sẵn để mã khách hàng đó chưa khai báo tham chiếu bằng cách sử dụng loại giao diện

Ví dụ về trường hợp 2 từ khuôn khổ .NET là ICollection.SyncLock.List<T> thực hiện ICollection chưa đoạn mã sau sẽ không biên dịch bởi vì các thành viên đã cố tình bị 'ẩn' như các nhà thiết kế của BCL không còn ủng hộ khóa bộ sưu tập theo cách này:

List<object> list = new List<object>(); 

lock (list.SyncRoot) // compiler fails here 
{ 
    // ... 
} 

Bất kỳ mã di sản của định dạng này sẽ vẫn làm việc , vì tham chiếu có loại ICollection rõ ràng:

ICollection list = new List<object>(); 

lock (list.SyncRoot) // no problem 
{ 
    // ... 
} 
+0

Cảm ơn, cho bạn câu trả lời vì bạn đã cung cấp tên chính xác của những gì đang diễn ra. –

+0

Được giảm hạng khi bạn gặp nhiều lỗi trong câu trả lời. Đầu tiên, lớp 'CanDoThisAndThat' thực hiện BA giao diện, chứ không phải hai giao diện. 'ICanDothisAndThat' nói rằng, khi được triển khai, bạn cũng phải thực hiện hai giao diện khác. Đồng thời, SyncRoot không được xác định rõ ràng bằng cách thực hiện để ẩn nó để ngăn cản việc sử dụng, nó được thực hiện thường để giữ cho các thành viên ít được sử dụng ra khỏi trang web, hoặc nếu thực tế là một giao diện được thực hiện sholdn't vấn đề. Xem http://msdn.microsoft.com/en-us/library/system.collections.icollection.syncroot.aspx và http://msdn.microsoft.com/en-us/library/bb356596.aspx. – Andy

+0

Không có nơi nào trong tài liệu đó nói rằng bạn không nên sử dụng SyncLock, cũng không được đánh dấu là lỗi thời, đó là những gì thực sự thực hiện khi một cái gì đó không còn được sử dụng. – Andy

4

Mỗi loại có một interface mapping (mà có thể được truy xuất với Type.GetInterfaceMap nếu bạn đợi nt để nhìn vào nó với sự phản ánh). Điều này về cơ bản nói, "Khi phương thức X trên giao diện Y được gọi, phương thức này Z là phương thức để gọi." Lưu ý rằng mặc dù nó không được hỗ trợ trong C#, có thể phương thức đích lập bản đồ có tên khác với tên phương thức giao diện! (VB rõ ràng hỗ trợ điều này, tôi tin.)

Trong trường hợp của bạn, bạn có ba phương pháp và mỗi phương pháp trong ba phương pháp tương ứng với một phương pháp trong một trong các giao diện liên quan.

Khi trình biên dịch đưa ra lời gọi đến phương thức ảo qua giao diện, IL tạo ra thông báo như "gọi IFoo.Bar trên đối tượng này" - và IFoo.Bar sau đó được giải quyết bằng bản đồ giao diện. Đôi khi bạn có thể cần sử dụng nó nếu bạn có chữ ký chỉ khác nhau về kiểu trả về, hoặc nếu bạn đang triển khai hai giao diện không đồng nhất có cùng tên phương thức nhưng phải làm những việc khác nhau. Bất cứ nơi nào bạn có thể tránh điều đó, hãy làm! Nó làm cho mã rất khó hiểu.

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