2012-04-27 21 views
11

Hay un montón de preguntas sobre este tema, pero tengo una versión ligeramente modificada.Determinar si una clase implementa una interfaz muy específica

tenemos el siguiente código:

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

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

Ahora, el giro de la historia: el método Implements_IFoo sólo debe devolver verdadero cuando el tipo implementa IFoo solamente y no cualquiera de las interfaces derivadas de IFoo. Para ilustrar aquí hay algunos ejemplos de este método:

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

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

Tenga en cuenta que no puede haber numerosas interfaces derivadas de IFoo y que no necesariamente saber de su existencia.

El método obvio es encontrar todas las interfaces derivadas de IFoo a través de la reflexión y luego simplemente verificar el tipo de (Bar) .GetInterfaces() es cualquiera de los que están presentes allí. Pero me preguntaba si alguien puede encontrar una solución más elegante.

PD La pregunta proviene de algún código que encontré que utiliza esta verificación en las clases (if(obj.GetType() == typeof(BaseClass)) { ... }). Estamos reemplazando clases con interfaces ahora ese código en particular. Además, por las dudas, estoy implementando esta verificación como una bandera booleana, por lo que esta pregunta es puramente hipotética.

+1

Tengo mucha curiosidad de por qué necesitas este tipo de introspección en primer lugar. Es probable que su diseño sea incorrecto. – tdammers

+0

Lea la pregunta 'hasta el final antes de comentar la próxima vez: ya expliqué que esta es una pregunta hipotética;) – Jefim

Respuesta

9

tuve una oportunidad porque sonaba divertido, y esto funciona para su ejemplo:

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

resultados:

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

No se ve para todas las interfaces derivadas de IFoo, simplemente recorre la cadena de implementación de herencia/interfaz y ve si IFoo está presente en cualquier nivel que no sea el nivel exacto del tipo.

También detecta si la interfaz se hereda a través del tipo de base. No estoy seguro si eso es lo que quieres.

Todavía, como ya han dicho otros, si esto es realmente un requisito para usted, entonces puede tener un problema con su diseño. (EDIT: acabo de dar cuenta de su pregunta es puramente hipotético, entonces está bien, por supuesto :).)

+0

Gracias, eso es exactamente lo que quise decir. Marcar su respuesta como correcta ya que fue la primera correcta. :) – Jefim

0

¿Intentó utilizar la palabra clave is?

BTW en general, si tiene un caso lógico donde alguna clase necesita ser del tipo de alguna clase base pero no de uno de los herederos, probablemente sea un diseño OO incorrecto, uno que podría violar el Liskov substitution principle.

+1

¿En un objeto' Tipo '? – mellamokb

+0

Nuevamente, 'is' no ayuda, ya que devolverá' true' para expr. 'Bar is IFoo' (y la salida deseada es' false' cuando Bar implementa IFoo 'a través de' IBar). Y si le importaba leer la pregunta a fondo, no tendría que molestarse en mencionar el diseño de Liskov y OO. Palabra clave: hipotético/teórico. ;) – Jefim

3

Consulte el siguiente sitio para ver ejemplos de cómo esto puede implementarse;

C# is keyword usage

Esencialmente se puede utilizar el 'es' palabra clave para determinar si el objeto habita un tipo de clase como parte de la misma pila de herencia de clases.

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 

En consonancia con su función de ejemplo:

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

Sé la palabra clave 'is' y no resuelve el problema. Por favor, mira la parte de mi pregunta con los ejemplos. Tenga en cuenta que IBar se deriva de IFoo. Así Bar también lo implementa a través de IBar. 'is' volverá a ser verdadero para expr. 'Bar es IFoo' pero ese no es el resultado deseado. – Jefim

0

La clase tipo tiene un método llamado GetInterface que puede utilizar.

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

que comprueba todas las interfaces en toda la jerarquía, y falla el segundo caso de uso '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

¡Gracias por la respuesta! Esto es exactamente lo que quise decir. – Jefim

1

Esto debería hacer el truco:

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

Probablemente hay formas más eficientes.

+0

Supongo que quería decir 'typeof (IFoo) .IsAssignableFrom (t)' en lugar de 't is IFoo', pero sí, esto es lo que se dice :) – Jefim

+0

Y por las dudas, ese código no verifica las clases base (bueno, eso no estaba claramente definido en mi pregunta) y la condición cuando un tipo no tiene ninguna interfaz (=> '.Cualquier (..)' devuelve falso entonces). – Jefim

Cuestiones relacionadas