2012-04-27 3 views
11

Có rất nhiều câu hỏi về chủ đề này, nhưng tôi có một phiên bản thay đổi nhỏ của nó.Xác định xem một lớp có thực hiện một giao diện rất cụ thể hay không

Chúng tôi có đoạn mã sau:

interface IFoo { } 
interface IBar : IFoo { } 
class Foo : IFoo { } 
class Bar : IBar { } 

bool Implements_IFoo(Type type) { /* ??? */ } 

Bây giờ, xoắn của câu chuyện: phương pháp Implements_IFoo chỉ nên trở thành sự thật khi Type chỉ và không thực hiện bất kỳ IFoo các giao diện có nguồn gốc từ IFoo. Để minh họa ở đây là một số ví dụ về phương pháp này:

Implements_IFoo(typeof(Foo)); // Should return true 

Implements_IFoo(typeof(Bar)); // Should return false as Bar type 
           // implements an interface derived from IFoo 

Lưu ý rằng có thể có nhiều giao diện bắt nguồn từ IFoo và bạn không nhất thiết phải biết về sự tồn tại của chúng.

Phương pháp hiển nhiên là tìm tất cả các giao diện bắt nguồn từ IFoo thông qua sự phản ánh và sau đó chỉ cần kiểm tra typeof (Bar) .GetInterfaces() là bất kỳ thứ gì có trong đó. Nhưng tôi đã tự hỏi nếu ai đó có thể đưa ra một giải pháp thanh lịch hơn.

PS Câu hỏi bắt nguồn từ một số mã tôi thấy sử dụng kiểm tra này trên các lớp học (if(obj.GetType() == typeof(BaseClass)) { ... }). Chúng tôi đang thay thế các lớp học bằng các giao diện ngay bây giờ với mã cụ thể đó. Ngoài ra, chỉ trong trường hợp - Tôi đang thực hiện kiểm tra này như là một lá cờ boolean, vì vậy câu hỏi này hoàn toàn là giả thuyết.

+1

Tôi thực sự tò mò tại sao bạn cần loại nội tâm này ngay từ đầu. Rất có thể thiết kế của bạn là sai. – tdammers

+0

Vui lòng đọc câu hỏi 'cho đến khi kết thúc trước khi nhận xét lần sau - Tôi đã giải thích rằng đây là một câu hỏi giả định;) – Jefim

Trả lời

9

Tôi đã có một thử vì nó nghe như vui vẻ, và điều này làm ví dụ của bạn:

bool ImplementsIFooDirectly(Type t) { 
    if (t.BaseType != null && ImplementsIFooDirectly(t.BaseType)) { 
     return false; 
    } 
    foreach (var intf in t.GetInterfaces()) { 
     if (ImplementsIFooDirectly(intf)) { 
      return false; 
     } 
    } 
    return t.GetInterfaces().Any(i => i == typeof(IFoo)); 
} 

kết quả:

ImplementsIFooDirectly(typeof(IFoo)); // false 
ImplementsIFooDirectly(typeof(Bar)); // false 
ImplementsIFooDirectly(typeof(Foo)); // true 
ImplementsIFooDirectly(typeof(IBar)); // true 

Nó không tìm kiếm tất cả các giao diện có nguồn gốc từ IFoo, nó chỉ di chuyển lên chuỗi kế thừa/giao diện thực hiện và xem liệu IFoo có mặt ở bất kỳ mức nào khác với mức chính xác của loại đó không.

Nó cũng phát hiện xem giao diện có được kế thừa thông qua loại cơ sở hay không. Không chắc chắn nếu đó là những gì bạn muốn.

Tuy nhiên, như những người khác đã nói rồi, nếu đây thực sự là một yêu cầu cho bạn, thì bạn có thể gặp vấn đề với thiết kế của mình. (EDIT: Chỉ cần nhận thấy câu hỏi của bạn là hoàn toàn giả thuyết Sau đó, nó là tốt tất nhiên :).)

+0

Cảm ơn, đó là chính xác những gì tôi có ý nghĩa. Đánh dấu câu trả lời của bạn là chính xác vì đây là câu trả lời đúng đầu tiên. :) – Jefim

0

Bạn đã cố gắng sử dụng từ khóa is? BTW nói chung, nếu bạn có một trường hợp hợp lý mà một số lớp cần phải thuộc loại một số lớp cơ sở nhưng không phải là một trong những người thừa kế, có thể là thiết kế OO sai, có thể vi phạm Liskov substitution principle.

+1

Trên đối tượng 'Loại'? – mellamokb

+0

Một lần nữa, 'is' không hỗ trợ vì nó sẽ trả về' true' cho expr. 'Bar là IFoo' (và đầu ra mong muốn là' false' khi Bar thực hiện IFoo 'thông qua' IBar). Và nếu bạn quan tâm để đọc các câu hỏi kỹ lưỡng, bạn sẽ không phải bận tâm đề cập đến thiết kế Liskov và OO. Từ khóa: hypothetical/theoretical. ;) – Jefim

3

Xem trang web sau để biết các ví dụ về cách thực hiện điều này;

C# is keyword usage

Về cơ bản bạn có thể sử dụng 'là' từ khóa để xác định xem các đối tượng sinh sống một kiểu lớp như một phần của nó của lớp thừa kế ngăn xếp.

class Director : Owner { } 
class Developer : Employee { } 
.. 
var dave = new Developer(); 
var steve = new Director(); 
var isEmployee = dave is Employee; // true 
var isAlsoEmploye = steve is Employee; // false 

Phù hợp với chức năng ví dụ của bạn:

bool Implements_Type(object instance, Type type) { 
return instance is type; 
} 
+0

Tôi biết từ khóa 'is' và nó không giải quyết được vấn đề. Vui lòng xem phần câu hỏi của tôi với các ví dụ. Lưu ý rằng IBar có nguồn gốc từ IFoo. Vì vậy Bar cũng thực hiện nó thông qua IBar. 'is' sẽ trả về true cho expr. 'Bar là IFoo' nhưng đó không phải là kết quả mong muốn. – Jefim

0

Các Loại lớp có một phương pháp gọi là GetInterface bạn có thể sử dụng.

bool Implements_IFoo(Type t) 
    { 
     return t.GetInterface(typeof(IFoo).Name) != null; 
    } 
+0

Mà kiểm tra tất cả các giao diện trong toàn bộ hệ thống phân cấp, và do đó không thành công trường hợp sử dụng thứ hai 'Implements_IFoo (typeof (Bar)); ' – mellamokb

2
static bool Implements_IFoo(Type type) 
{ 
    if (typeof(IFoo).IsAssignableFrom(type.BaseType)) 
    return false; 

    var barInterfaces = type.GetInterfaces() 
    .Where(iface => typeof(IFoo).IsAssignableFrom(iface)) 
    .ToArray(); 

    return barInterfaces.Length > 0 
    && barInterfaces.Length == barInterfaces.Count(iface => iface == typeof(IFoo)); 
} 
static bool Implements_IFoo_Optimized(Type type) 
{ 
    if (typeof(IFoo).IsAssignableFrom(type.BaseType)) 
    return false; 

    return type.GetInterfaces() 
    .Where(iface => typeof(IFoo).IsAssignableFrom(iface)) 
    .Count() == 1; 
} 
+0

Cảm ơn câu trả lời! Đây chính là điều tôi muốn nói. – Jefim

1

này nên làm như lừa:

public bool ImplementsIFooOnly(Type type) 
{ 
    return !type.GetInterfaces().Any(t => 
       { 
        return t is IFoo && !t.Equals(typeof(IFoo)); 
       }); 
} 

Có lẽ những cách hiệu quả hơn.

+0

Tôi đoán bạn có nghĩa là 'typeof (IFoo) .IsAssignableFrom (t)' thay vì 't là IFoo', nhưng có, đây là những thứ :) – Jefim

+0

Và chỉ trong trường hợp - mã đó không kiểm tra các lớp cơ sở (tốt, rằng không được xác định rõ ràng trong câu hỏi của tôi) và điều kiện khi một kiểu không có bất kỳ giao diện nào (=> '.Any (..)' trả về false sau đó). – Jefim