2011-03-15 21 views
17

Tengo una clase como la siguiente. GetInterfaces() diceObtenga solo la interfaz directa en lugar de todas?

Si el objeto Type actual representa un parámetro de tipo en la definición de un tipo genérico o método genérico, este método busca en la interfaz limitaciones y las interfaces heredados de la clase o interfaz limitaciones .

¿Es posible para mí no obtener ninguna interfaz heredada? Cuando uso GetInterfaces en ABC, solo quiero ver DEF, no DEF y GHI.

interface DEF : GHI {...} 
class ABC : DEF {...} 
+1

Dado que yo estoy sólo en mi iPad ¡No puedo código de prueba o buscar todos los métodos, pero aquí hay un pensamiento. ¿Podrían encontrar todas las interfaces que implementa su tipo (incluidas las heredadas), luego pasar al tipo base de su tipo, encontrar todas las interfaces * que * escriba implementa y restar aquellas del primer conjunto? Creo que se quedaría con lo que ABC agregó de interfaces. Si alguien quiere "robar" este comentario y escribir una respuesta real, por favor hazlo, no será hasta mañana hasta que regrese a mi computadora. –

+0

GetInterfaces() es un método en la clase Type. –

+0

Ah, mis disculpas, su "tipo de base" es una interfaz, entonces no lo sé. –

Respuesta

24

En primer lugar, el fragmento de MSDN que ha publicado no tiene nada que ver con su pregunta real. Se trata de cuando se tiene, por ejemplo, un tipo genérico como class Foo<T> where T : IEnumerable, y se intenta llamar GetInterfaces relativa a la recepción de parámetros T, por ejemplo a través typeof(Foo<>).GetGenericArguments().Single().GetInterfaces().

En segundo lugar, se especifica un poco mal el problema. Tenga en cuenta que cuando una clase implementa una interfaz, debe implementar todos de las interfaces 'heredadas' por esa interfaz. Es simplemente una característica de conveniencia C# que le permite omitir las interfaces heredadas en la declaración de clase. En su ejemplo, es perfectamente legal (y no es diferente) a explícitamente incluir el 'heredada' GHI interfaz:

class ABC : DEF, GHI {...} 

he asumido que lo que realmente quiere hacer es encontrar un 'mínimo conjunto de interfaces que "cubren" todas las interfaces implementadas del tipo. Esto da como resultado una versión ligeramente simplificada del Set cover problem.

Aquí hay una manera de resolverlo, sin ningún tipo de intento algorítmicamente eficiente. La idea es producir el conjunto de interfaz mínimo filtrando aquellas interfaces que son ya implementadas porotras interfaces implementadas por el tipo.

Type type = ... 

var allInterfaces = type.GetInterfaces();  
var minimalInterfaces = from iType in allInterfaces 
         where !allInterfaces.Any(t => t.GetInterfaces() 
                 .Contains(iType)) 
         select iType; 

( EDITAR - Aquí hay una manera mejor de hacer lo anterior:

var minimalInterfaces = allInterfaces.Except 
         (allInterfaces.SelectMany(t => t.GetInterfaces())); 

)

Por ejemplo, para List<int>:

allInterfaces: 

System.Collections.Generic.IList`1[System.Int32] 
System.Collections.Generic.ICollection`1[System.Int32] 
System.Collections.Generic.IEnumerable`1[System.Int32] 
System.Collections.IEnumerable 
System.Collections.IList 
System.Collections.ICollection 

minimalInterfaces: 

System.Collections.Generic.IList`1[System.Int32] 
System.Collections.IList 

Tenga en cuenta que esta solución cubre interfaz 'hierarchies' solamente (que es lo que parece querer), no cómo se relacionan con la clase clase jerarquía. En particular, no presta atención a donde en la jerarquía de una clase se implementó por primera vez una interfaz.

Por ejemplo, supongamos que tenemos:

interface IFoo { } 
interface IBar : IFoo { } 
interface IBaz { } 

class Base : IBar { } 
class Derived : Base, IBaz { } 

Ahora bien, si se intenta utilizar la solución que he descrito para obtener el mínimo establecido para la interfaz de Derived, se llega a IBaz, así como IBar. Si no quiere IBar, debería esforzarse más: eliminar las interfaces implementadas por las clases base. La forma más sencilla de hacerlo sería eliminar de la interfaz mínima: establecer las interfaces implementadas por la clase base inmediata de la clase, como se menciona en la respuesta de @ MikeEast.

+0

+1 nice one, y funciona para interfaces – BrokenGlass

+0

Excelente respuesta. –

0

La misma página de MSDN dice

El método GetInterfaces no interfaces de retorno en un orden en particular, como alfabético o orden de la declaración. Su código no debe según el orden en que se devuelven las interfaces , porque el orden de varía.

Así que no, no puede omitir las interfaces.

+0

El OP no intenta omitir las interfaces, sino que recupera solo las interfaces implementadas directamente. –

+0

Creo que el principal problema aquí es que una vez que un tipo implementa una interfaz, ya no hay un concepto de "implementación directa". Tendrá que analizar el gráfico de la "herencia" de la interfaz y encontrar el resultado más plausible. –

3

Esta es una bonita pieza de un duplicate question:

public static class TypeExtensions { 
    public static IEnumerable<Type> GetInterfaces(this Type type, bool includeInherited) 
    { 
     if (includeInherited || type.BaseType == null) 
     return type.GetInterfaces(); 
     else 
     return type.GetInterfaces().Except(type.BaseType.GetInterfaces()); 
    } 
} 

y uso:

foreach(Type ifc in typeof(Some).GetInterfaces(false)) { 
    Console.WriteLine(ifc); 
} 
+0

problema con esto es que no funcionará para, por ejemplo, 'IList ', tuve una solución similar basada en el comentario de @ Lasse – BrokenGlass

+0

Ah, para la cosa 'BaseType'. No lo vi. –

0

¿Qué tal esto para heirachy herencia de interfaces?

public static Map GetTypeInheritance(Type type) 
    { 
     //get all the interfaces for this type 
     var interfaces = type.GetInterfaces(); 

     //get all the interfaces for the ancestor interfaces 
     var baseInterfaces = interfaces.SelectMany(i => i.GetInterfaces()); 

     //filter based on only the direct interfaces 
     var directInterfaces = interfaces.Where(i => baseInterfaces.All(b => b != i)); 

     Map map = new Map 
      { 
       Node = type, 
       Ancestors = directInterfaces.Select(GetTypeInheritance).ToList() 
      }; 

     return map; 
    } 

    public class Map 
    { 
     public Type Node { get; set; } 
     public List<Map> Ancestors { get; set; } 
    } 
0

Esta pregunta se duplica tanto here y here. En cualquier caso, aquí está mi código concisa que tiene en cuenta las cuestiones planteadas en este hilo por @Ani y @Mikael:

var actualInterfaces = type.GetInterfaces(); 
foreach (var result in actualInterfaces 
    .Except(type.BaseType?.GetInterfaces() ?? Enumerable.Empty<Type>()) //See https://stackoverflow.com/a/1613936 
    .Except(actualInterfaces.SelectMany(i => i.GetInterfaces())) //See https://stackoverflow.com/a/5318781 
) yield return result; 
Cuestiones relacionadas