2011-09-27 12 views
9

Estoy tratando de realizar una consulta sobre las interfaces de una clase a través de la reflexión, sin embargo, el método Type.GetInterfaces() también devuelve todas las interfaces heredadas.¿Buscar solo interfaces no heredadas?

etc

public class Test : ITest { } 

public interface ITest : ITesting { } 

El código

typeof(Test).GetInterfaces(); 

devolverá un Type[] que contiene tanto ITest y ITesting, en tanto que sólo quiero ITest, ¿hay otro método que le permite especificar la herencia?

Gracias, Alex.

EDIT: De las respuestas a continuación recogí esto,

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

Lo anterior parece funcionar, me corrija en los comentarios si no lo hace

+3

¿Qué pasa si se trata de 'prueba de clase pública: ITest, ITesting'? ¿Por qué quieres esto? – SLaks

+3

Porque me gustaría saber de qué interfaces está heredando directamente la clase? y no las interfaces de las que hereda indirectamente, para generar dinámicamente nuevos tipos. ¿Importa por qué? –

+5

Estrictamente hablando, no * hereda * interfaces, * las implementa *, por lo que la clase 'Prueba 'proporciona una implementación de' ITest' y 'ITesting' en este caso. El hecho de que 'ITest'" herede "de' ITesting' simplemente significa que cualquier tipo que implemente 'ITest' debe proporcionar también una implementación de' ITesting'. – LukeH

Respuesta

6

Usted puede tratar algo como esto:

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

Creo que hay una forma más elegante, pero no puedo pensar en eso ahora ...

modo, si usted tiene algo como esto:

public interface A : B 
    { 
    } 

    public interface B : C 
    { 
    } 

    public interface C 
    { 
    } 

    public interface D 
    { 
    } 

    public class MyType : A, D 
    { 
    } 

El código devolverá A y D

0

intente esto:

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

Esto supone que conoce la interfaz específica que quiere encontrar. Si él ya lo sabía, probablemente no necesitaría reflexionar. –

+0

No es muy útil, necesito una solución genérica que funcione sin que yo tenga que saber el nombre de la interfaz. –

+0

tienes razón, lo malentendí. intente esto de nuevo – ojlovecd

4

Un experto más grande en .NET puede corregirme si me equivoco, pero no creo que esto sea posible. Internamente, creo que .NET Framework en realidad no mantiene esa jerarquía, y se aplana cuando se compila con código IL.

Por ejemplo, el código C#:

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

interface I1 
{ 
} 

interface I2 : I1 
{ 
} 

Después de que se construyó en el código IL, es:

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

¿Qué es exactamente el mismo que class Program : I1, I2


Sin embargo, también en el IL es:

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

Esto significa que usted podría escribir algo de lógica para obtener (de mi ejemplo) I1 y I2 de la clase Program, a continuación, consultar cada una de esas interfaces para ver si implementan uno de los otros ... En otras palabras , ya que contiene typeof(I2).GetInterfaces()I1, entonces se puede inferir que desde typeof(Program).GetInterfaces() vuelve I1 y I2, entonces podría Program no hereda directamente I1 en el código.

subrayo podría no porque esto también es válido el código C# y haría que el mismo código IL (y también los mismos resultados reflexión):

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

interface I1 
{ 
} 

interface I2 : I1 
{ 
} 

Ahora Program tanto directa como indirectamente hereda I1 ..

1

En mi intento anterior no pude tener éxito.

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

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

    foreach (var t in directTypes) 
    { 

    } 

Espero que esto ayude a alguien.

+0

Buscando comentarios positivos del bajista. – adatapost

+1

esto * parece * como debería funcionar perfectamente. sintaxis alternativa no LINQ: 'typeof (Test) .GetInterfaces(). Where (i => i.GetInterfaces(). Length> = 1) .SingleOrDefault();' –

+1

¿Esto no se caería si la clase implementara directamente dos interfaces. 'Prueba: ITestInterface1, ITestInterface2'? (Al caer me refiero a dejar de mostrar que la clase implementa directamente más de 1 interfaz) – Phill

1

Parece que no hay llamada a un método trivial para hacer esto como básicamente los siguientes son exactamente lo mismo cuando se compila:

MyClass : IEnumerable<bool> 

y

MyClass : IEnumerable<bool>,IEnumerable 

Puede interrogar a cada interfaz y pedir su interfaces. Y mira si están en la lista de los formadores. Inusualmente, para las clases GetInterfaces es recursivo. Es decir, obtiene todos los niveles de herencia. Para las interfaces no es recursivo. Por ejemplo: IList devuelve IList y ICollection, pero no menciona IEnumerable que está implementado por ICollection.

Sin embargo, lo más probable es que esté interesado en los métodos implementados únicamente por cada interfaz y su enlace, en cuyo caso puede usar el método 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

No es posible simplemente recuperar las interfaces inmediatos, pero tenemos los metadatos Tipo necesaria para averiguarlo.

Si tenemos una lista aplanada de interfaces de toda la cadena de herencia, y cada interfaz puede decirnos cuál de sus hermanos también implementa/requiere (lo que hacen), podemos eliminar recursivamente todas las interfaces implementadas o requeridas en un padre.

Este enfoque es un poco más agresivo, en el que si se declara IFoo y IBar de la clase inmediata y IFoo por requerimiento IBar, será eliminado (pero realmente, ¿qué es esto más que un ejercicio de curiosidad? la utilidad práctica de esto es claro para mí ...)

este código es feo como el infierno, pero yo sólo lo tiró juntos en un/desnuda fresca MonoDevelop instalar ...

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); 
    } 
} 
Cuestiones relacionadas