2011-09-27 35 views
9

Tôi đang cố gắng thực hiện một truy vấn trên các giao diện của một lớp thông qua sự phản chiếu, tuy nhiên phương thức Type.GetInterfaces() trả về tất cả các giao diện kế thừa.Chỉ tìm giao diện không được kế thừa?

vv

public class Test : ITest { } 

public interface ITest : ITesting { } 

typeof(Test).GetInterfaces(); 

sẽ trả về một Type[] chứa cả ITestITesting, nơi như tôi chỉ muốn ITest, là có một phương pháp cho phép bạn chỉ định thừa kế?

Cảm ơn, Alex.

EDIT: Từ các câu trả lời dưới đây tôi thu thập được này,

Type t; 
t.GetInterfaces().Where(i => !t.GetInterfaces().Any(i2 => i2.GetInterfaces().Contains(i))); 

dường như ở trên để làm việc, chính xác cho tôi trong các ý kiến ​​nếu nó không

+3

Điều gì xảy ra nếu nó là 'lớp công khai Kiểm tra: ITest, ITesting'? Tại sao bạn muốn điều này? – SLaks

+3

Bởi vì tôi muốn biết giao diện nào của lớp được kế thừa trực tiếp? và không phải là giao diện mà nó được kế thừa từ gián tiếp, để tạo động các kiểu mới. Liệu nó có quan trọng không? –

+5

Nói đúng, bạn không * kế thừa * giao diện, bạn * thực hiện * chúng, do đó, lớp 'Kiểm tra' đang cung cấp việc triển khai' ITest' và 'ITesting' trong trường hợp này. Thực tế là 'ITest'" thừa hưởng "từ' ITesting' đơn giản có nghĩa là bất kỳ kiểu nào thực hiện 'ITest' cũng phải cung cấp một sự thực thi' ITesting'. – LukeH

Trả lời

6

Bạn có thể thử một cái gì đó như thế này:

Type[] interfaces = typeof(Test).GetInterfaces(); 
var exceptInheritedInterfaces = interfaces.Except(interfaces.SelectMany(t => t.GetInterfaces())); 

Tôi nghĩ rằng có một cách thanh lịch hơn, nhưng tôi không thể nghĩ về nó ngay bây giờ ...

như vậy, nếu bạn có một cái gì đó như thế này:

public interface A : B 
    { 
    } 

    public interface B : C 
    { 
    } 

    public interface C 
    { 
    } 

    public interface D 
    { 
    } 

    public class MyType : A, D 
    { 
    } 

Mã sẽ trả lại AD

0

thử điều này:

Type t = typeof(Test); 
    int max = 0; 
    Type result = null; 
    foreach (Type type in t.GetInterfaces()) 
    { 
     int len = type.GetInterfaces().Length; 
     if (len > max) 
     { 
      max = len; 
      result = type; 
     } 
    } 
    if (result != null) 
     Console.WriteLine(result.FullName); 
+2

Điều này giả định anh ấy biết giao diện cụ thể mà anh ấy muốn tìm. Nếu anh đã biết điều đó, anh có thể sẽ không cần phản ánh. –

+0

Không phải là rất hữu ích, tôi cần một giải pháp chung mà sẽ làm việc mà không cần tôi phải biết tên của giao diện. –

+0

bạn nói đúng, tôi hiểu lầm nó. thử lại lần nữa – ojlovecd

4

Một chuyên gia lớn hơn trong .NET có thể sửa tôi nếu tôi sai, nhưng tôi không tin điều này là có thể. Tôi tin rằng khuôn khổ .NET không thực sự duy trì hệ thống phân cấp đó, và nó được làm phẳng khi nó được biên dịch thành mã IL.

Ví dụ, đoạn code C#:

class Program : I2 
{ 
    static void Main(string[] args) 
    { 
    } 
} 

interface I1 
{ 
} 

interface I2 : I1 
{ 
} 

Sau khi nó được xây dựng vào mã IL, đó là:

.class private auto ansi beforefieldinit ReflectionTest.Program 
     extends [mscorlib]System.Object 
     implements ReflectionTest.I2, 
        ReflectionTest.I1 
{ 
    ... 

Đó là chính xác giống như class Program : I1, I2


Tuy nhiên, cũng trong IL là:

.class interface private abstract auto ansi ReflectionTest.I2 
     implements ReflectionTest.I1 
{ 
    ... 

Điều này có nghĩa rằng bạn có thể viết một số logic để có được (từ ví dụ của tôi) I1I2 từ lớp Program, sau đó truy vấn mỗi người giao diện để xem họ thực hiện một trong những người khác ... Nói cách khác , vì typeof(I2).GetInterfaces() chứa I1, sau đó bạn có thể suy ra rằng kể từ khi typeof(Program).GetInterfaces() lợi nhuận I1I2, sau đó Programthể không trực tiếp kế thừa I1 trong mã.

Tôi nhấn mạnh có thể không vì đây cũng là C# mã hợp lệ và sẽ làm cho cùng mã IL (và cũng là kết quả phản ánh tương tự):

class Program : I1, I2 
{ 
    static void Main(string[] args) 
    { 
    } 
} 

interface I1 
{ 
} 

interface I2 : I1 
{ 
} 

Bây giờ Program cả trực tiếp và gián tiếp thừa hưởng I1 ..

1

Trong nỗ lực trước đó của tôi, tôi không thể thành công.

Type[] types = typeof(Test).GetInterfaces(); 

var directTypes = types.Except 
        (types.SelectMany(t => t.GetInterfaces())); 

    foreach (var t in directTypes) 
    { 

    } 

Hy vọng điều này sẽ giúp ai đó.

+0

Tìm kiếm các nhận xét tích cực từ trình gỡ xuống. – adatapost

+1

điều này * trông * giống như nó sẽ hoạt động hoàn hảo. thay thế cú pháp không phải LINQ: 'typeof (Kiểm tra) .GetInterfaces(). Trường hợp (i => i.GetInterfaces(). Length> = 1) .SingleOrDefault();' –

+1

Điều này sẽ không rơi nếu lớp được triển khai trực tiếp hai giao diện. 'Kiểm tra: ITestInterface1, ITestInterface2'? (do ngã hơn tôi có nghĩa là bỏ bê để hiển thị các lớp trực tiếp thực hiện nhiều hơn 1 giao diện) – Phill

1

Nó xuất hiện không có phương pháp gọi tầm thường để làm điều này là cơ bản sau đây là giống hệt nhau khi biên soạn:

MyClass : IEnumerable<bool> 

MyClass : IEnumerable<bool>,IEnumerable 

Bạn có thể thẩm vấn từng giao diện và yêu cầu của mình giao diện. Và xem họ có trong danh sách formers không. Bất thường, đối với các lớp GetInterfaces là đệ quy. Đó là để nói rằng nó được tất cả các cấp thừa kế. Đối với giao diện, nó không đệ quy. Ví dụ: IList trả về IListICollection, nhưng không đề cập đến số IEnumerable được triển khai bởi ICollection.

Tuy nhiên, bạn có nhiều khả năng quan tâm đến các phương pháp được triển khai duy nhất bởi mỗi giao diện và ràng buộc của chúng trong trường hợp bạn có thể sử dụng phương thức GetInterfaceMap(Type).

0
Type t = typeof(Test); 
    int max = 0; 
    List<Type> results = new List<Type>(); 
    foreach (Type type in t.GetInterfaces()) 
    { 
     int len = type.GetInterfaces().Length; 
     if (len > max) 
     { 
      max = len; 
      results.Add(type); 
     } 
    } 
    if (results.Count > 0) 
     foreach (Type type in results) 
      Console.WriteLine(type.FullName); 
2

Nó không thể chỉ đơn giản là lấy các giao diện trước mắt, nhưng chúng tôi có Type metadata cần thiết để con nó ra.

Nếu chúng ta có một danh sách giao diện phẳng từ toàn bộ chuỗi kế thừa, và mỗi giao diện có thể cho chúng ta biết các anh chị em của nó cũng thực hiện/yêu cầu (chúng làm), chúng tôi có thể loại bỏ đệ quy mọi giao diện được thực hiện hoặc yêu cầu trên một phụ huynh.

Cách tiếp cận này là một chút quá hung hăng, trong đó nếu bạn khai báo IFooIBar trên lớp ngay lập tức VÀ IFoo là yêu cầu của IBar, nó sẽ bị loại bỏ (nhưng thực sự, đây là những gì nhiều hơn một bài tập trong sự tò mò? tính hữu ích thiết thực của việc này là không rõ ràng với tôi ...)

mã này là xấu xí như địa ngục, nhưng tôi chỉ ném nó với nhau trong một/trần tươi MonoDevelop cài đặt ...

public static void Main (string[] args) 
{ 
    var nonInheritedInterfaces = typeof(Test).GetImmediateInterfaces(); 
    foreach(var iface in nonInheritedInterfaces) 
    { 
     Console.WriteLine(iface); 
    } 
    Console.Read(); 
} 

class Test : ITest { } 

interface ITest : ITestParent { } 

interface ITestParent { } 

public static class TypeExtensions 
{ 
    public static Type[] GetImmediateInterfaces(this Type type) 
    { 
     var allInterfaces = type.GetInterfaces(); 
     var nonInheritedInterfaces = new HashSet<Type>(allInterfaces); 
     foreach(var iface in allInterfaces) 
     { 
      RemoveInheritedInterfaces(iface, nonInheritedInterfaces); 
     } 
     return nonInheritedInterfaces.ToArray(); 
    } 

    private static void RemoveInheritedInterfaces(Type iface, HashSet<Type> ifaces) 
    { 
     foreach(var inheritedIface in iface.GetInterfaces()) 
     { 
      ifaces.Remove(inheritedIface); 
      RemoveInheritedInterfaces(inheritedIface, ifaces); 
     } 
    } 
} 

private static void RemoveInheritedInterfaces(Type iface, Dictionary<Type, Type> interfaces) 
{ 
    foreach(var inheritedInterface in iface.GetInterfaces()) 
    { 
     interfaces.Remove(inheritedInterface); 
     RemoveInheritedInterfaces(inheritedInterface, interfaces); 
    } 
} 
Các vấn đề liên quan