2009-02-02 13 views

Respuesta

306

Mediante el uso de la responder desde TCKs también se puede hacer con la siguiente consulta LINQ:

bool isBar = foo.GetType().GetInterfaces().Any(x => 
    x.IsGenericType && 
    x.GetGenericTypeDefinition() == typeof(IBar<>)); 
+1

¡Esta es una solución muy elegante! Los otros que he visto en SO usan bucles foreach o consultas LINQ más largas. Sin embargo, tenga en cuenta que para usar esto, necesita tener .NET framework 3.5. –

+7

Te recomiendo que hagas de este un método de extensión a la http://bit.ly/ccza8B - ¡lo limpiarás bastante bien! –

+1

Dependiendo de sus necesidades, es posible que deba recurrir en las interfaces devueltas. –

4

Tiene que verificar contra un tipo construido de la interfaz genérica.

Usted tendrá que hacer algo como esto:

foo is IBar<String> 

porque IBar<String> representa ese tipo construido. La razón por la que tiene que hacer esto es porque si T no está definido en su cheque, el compilador no sabe si se refiere a IBar<Int32> o IBar<SomethingElse>.

31

usted tiene que ir a través del árbol de herencia y encontrar todas las interfaces para cada clase en el árbol, y compara typeof(IBar<>) con el resultado de llamar Type.GetGenericTypeDefinition si la interfaz es genérico. Todo es un poco doloroso, sin duda.

Consulte this answer y these ones para obtener más información y código.

+0

¿por qué no acaba de emitir a IBar y comprobar nulo? (Me refiero a casting con 'como', por supuesto) –

+3

T es desconocido y no se puede convertir a un tipo específico. – sduplooy

+0

@sduplooy: tal vez me falta algo ¿cómo puede ser desconocido? compilaría la clase pública Foo: IFoo {} –

19
public interface IFoo<T> : IBar<T> {} 
public class Foo : IFoo<Foo> {} 

var implementedInterfaces = typeof(Foo).GetInterfaces(); 
foreach(var interfaceType in implementedInterfaces) { 
    if (false == interfaceType.IsGeneric) { continue; } 
    var genericType = interfaceType.GetGenericTypeDefinition(); 
    if (genericType == typeof(IFoo<>)) { 
     // do something ! 
     break; 
    } 
} 
+1

Como typeof (Foo) devuelve el objeto System.Type (que describe Foo), la llamada GetType() siempre devolverá el tipo para System.Type. Deberías cambiar a typeof (Foo) .GetInterfaces() –

3

En primer lugar public class Foo : IFoo<T> {} no se compila porque es necesario especificar una clase en lugar de T, pero suponiendo que hacer algo como public class Foo : IFoo<SomeClass> {}

continuación, si lo hace

Foo f = new Foo(); 
IBar<SomeClass> b = f as IBar<SomeClass>; 

if(b != null) //derives from IBar<> 
    Blabla(); 
9

Como una extensión método de ayuda

public static bool Implements<I>(this Type type, I @interface) where I : class 
{ 
    if(((@interface as Type)==null) || !(@interface as Type).IsInterface) 
     throw new ArgumentException("Only interfaces can be 'implemented'."); 

    return (@interface as Type).IsAssignableFrom(type); 
} 

Ejemplo de uso:

var testObject = new Dictionary<int, object>(); 
result = testObject.GetType().Implements(typeof(IDictionary<int, object>)); // true! 
+2

"IsAssignableFrom" era exactamente lo que estaba buscando - gracias – Jesper

+14

Esto no significa trabajo para el requisito del solicitante de no conocer el parámetro de tipo genérico. De su ejemplo testObject.GetType(). Implements (typeof (IDictionary <,>)); devolverá falso. – ctusch

4

estoy usando una versión ligeramente más simple del método de extensión @GenericProgrammers:

public static bool Implements<TInterface>(this Type type) where TInterface : class { 
    var interfaceType = typeof(TInterface); 

    if (!interfaceType.IsInterface) 
     throw new InvalidOperationException("Only interfaces can be implemented."); 

    return (interfaceType.IsAssignableFrom(type)); 
} 

Uso:

if (!featureType.Implements<IFeature>()) 
     throw new InvalidCastException(); 
+3

Todavía no funciona según el requisito de la pregunta original que es para interfaces genéricas. – nathanchere

0

No debe haber nada malo lo siguiente:

Para crédito adicional se puede coger AmbiguousMatchException si desea proporcionar un tipo de parámetro genérico específico con su consulta IBar.

+0

Bueno, generalmente es mejor evitar usar literales de cadena cuando sea posible. Este enfoque dificultaría la refactorización de la aplicación, ya que el cambio de nombre de la interfaz IBar no cambiaría el literal de la cadena, y el error solo sería detectable en el tiempo de ejecución. – andyroschy

+0

Por más que estoy de acuerdo con el comentario anterior sobre el uso de 'magic strings', etc., este sigue siendo el mejor enfoque que he encontrado. Lo suficientemente cerca: probando que PropertyType.Name iguale "IWhatever'1". – nathanchere

+0

¿Por qué no esto? 'bool implementsGeneric = (anObject.Implements (typeof (IBar <>). Name)! = null);' –

3

Para abordar completamente el sistema de tipos, creo que debe manejar la recursividad, p. IList<T>: ICollection<T>: IEnumerable<T>, sin el cual no sabría que IList<int> finalmente implementa IEnumerable<>.respuesta

/// <summary>Determines whether a type, like IList&lt;int&gt;, implements an open generic interface, like 
    /// IEnumerable&lt;&gt;. Note that this only checks against *interfaces*.</summary> 
    /// <param name="candidateType">The type to check.</param> 
    /// <param name="openGenericInterfaceType">The open generic type which it may impelement</param> 
    /// <returns>Whether the candidate type implements the open interface.</returns> 
    public static bool ImplementsOpenGenericInterface(this Type candidateType, Type openGenericInterfaceType) 
    { 
     Contract.Requires(candidateType != null); 
     Contract.Requires(openGenericInterfaceType != null); 

     return 
      candidateType.Equals(openGenericInterfaceType) || 
      (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition().Equals(openGenericInterfaceType)) || 
      candidateType.GetInterfaces().Any(i => i.IsGenericType && i.ImplementsOpenGenericInterface(openGenericInterfaceType)); 

    } 
1

En caso de que quería un método de extensión que apoyaría tipos base genéricos, así como interfaces, he ampliado de sduplooy:

public static bool InheritsFrom(this Type t1, Type t2) 
    { 
     if (null == t1 || null == t2) 
      return false; 

     if (null != t1.BaseType && 
      t1.BaseType.IsGenericType && 
      t1.BaseType.GetGenericTypeDefinition() == t2) 
     { 
      return true; 
     } 

     if (InheritsFrom(t1.BaseType, t2)) 
      return true; 

     return 
      (t2.IsAssignableFrom(t1) && t1 != t2) 
      || 
      t1.GetInterfaces().Any(x => 
       x.IsGenericType && 
       x.GetGenericTypeDefinition() == t2); 
    } 
1

método para comprobar si el tipo hereda o implementa un genérico tipo:

public static bool IsTheGenericType(this Type candidateType, Type genericType) 
    { 
     return 
      candidateType != null && genericType != null && 
      (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition() == genericType || 
      candidateType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericType) || 
      candidateType.BaseType != null && candidateType.BaseType.IsTheGenericType(genericType)); 
    } 
Cuestiones relacionadas