Asumen las siguientes definiciones de tipo:

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

¿Cómo puedo averiguar si el tipo Foo implementa la interfaz genérica IBar<T> cuando sólo el alterados tipo está disponible?

InformationsquelleAutor sduplooy | 2009-02-02

12 Comentarios

  1. 360

    Mediante la respuesta de TcKs también se puede hacer con la siguiente consulta LINQ:

    bool isBar = foo.GetType().GetInterfaces().Any(x =>
      x.IsGenericType &&
      x.GetGenericTypeDefinition() == typeof(IBar<>));
    • Esta es una solución muy elegante! Los otros que he visto en PARA uso de bucles foreach o más consultas de LINQ. Tenga en cuenta que para utilizar este servicio, usted necesita tener .NET framework 3.5.
    • Te recomiendo que hacen de este un método de extensión a la bit.ly/ccza8B — se limpia esta bastante bien!
    • Dependiendo de sus necesidades, usted puede encontrar que usted necesita para reaparecer en las interfaces devuelto.
    • Yo diría que esto debería haber sido implementadas .net es mucho mejor… como un núcleo … como miembro.Implementa(IBar) o CustomType.Implementa(IBar), o mejor aún, el uso de una palabra clave «es» …. Estoy explorando c# y estoy más luego, poco decepcionado .net ahora …
    • menor de la suma: si IBar tiene varios tipos genéricos, deberá indicar esta como: typeof(IBar<,,,>) con comas que actúan como marcadores de posición
  2. 32

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

    Ver esta respuesta y estos para más información y código.

    • ¿por qué no acaba de lanzar para IBar<SomeClass> y comprobar el valor null? (Me refiero a la fundición con ‘como’ por supuesto)
    • T es desconocido y no se puede convertir a un tipo específico.
    • tal vez me estoy perdiendo algo, ¿cómo puede ser desconocido? sería compilar public class Foo : IFoo<T> {}
  3. 22
    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;
        }
    }
    • Desde typeof( Foo ) devuelve el Sistema.Tipo de objeto (describir Foo), el GetType() la llamada devolverá siempre el tipo de Sistema.Tipo. Usted debe cambiar a typeof(Foo).GetInterfaces()
  4. 9

    Como un método auxiliar de extensión

    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!
    • «IsAssignableFrom» era exactamente lo que estaba buscando, gracias
    • Esto no funciona para el autor de la pregunta del requisito de no saber el parámetro de tipo genérico. A partir de su ejemplo testObject.GetType().Implementa(typeof(IDictionary<,>)); devolverá falso.
    • entonces, alguna solución para eso?
  5. 5

    Estoy usando un poco la versión más simple de @GenericProgrammers método de extensión:

    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();
    • Todavía no funciona como por la pregunta original del requisito que es para interfaces genéricas.
  6. 4

    Usted tiene que comprobar en contra de un tipo construido de la interfaz genérica.

    Usted tendrá que hacer algo como esto:

    foo is IBar<String>

    porque IBar<String> representa que tipo construido. La razón que usted tiene que hacer esto es porque si T no está definido en su cheque, el compilador no sé si te refieres a IBar<Int32> o IBar<SomethingElse>.

  7. 4

    Para abordar el tipo de sistema completo, yo creo que usted necesita para manejar la recursividad, por ejemplo,IList<T> : ICollection<T> : IEnumerable<T>, sin la cual no se sabe que IList<int> en última instancia implementa IEnumerable<>.

        ///<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));
    
        }
  8. 3

    Primero de todos public class Foo : IFoo<T> {} no compila porque necesita especificar una clase en lugar de T, pero suponiendo que hacer algo como public class Foo : IFoo<SomeClass> {}

    a continuación, si usted

    Foo f = new Foo();
    IBar<SomeClass> b = f as IBar<SomeClass>;
    
    if(b != null)  //derives from IBar<>
        Blabla();
  9. 1

    En caso de que usted quisiera un método de extensión que apoyaría genérico tipos de base, así como interfaces, he ampliado sduplooy la respuesta:

        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);
        }
  10. 1

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

       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));
        }
  11. 0

    Tratar la siguiente extensión.

    public static bool Implements(this Type @this, Type @interface)
    {
        if (@this == null || @interface == null) return false;
        return @interface.GenericTypeArguments.Length>0
            ? @interface.IsAssignableFrom(@this)
            : @this.GetInterfaces().Any(c => c.Name == @interface.Name);
    }

    Para probarlo. crear

    public interface IFoo { }
    public interface IFoo<T> : IFoo { }
    public interface IFoo<T, M> : IFoo<T> { }
    public class Foo : IFoo { }
    public class Foo<T> : IFoo { }
    public class Foo<T, M> : IFoo<T> { }
    public class FooInt : IFoo<int> { }
    public class FooStringInt : IFoo<string, int> { }
    public class Foo2 : Foo { }

    y el método de prueba

    public void Test()
    {
        Console.WriteLine(typeof(Foo).Implements(typeof(IFoo)));
        Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo)));
        Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<>)));
        Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<int>)));
        Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<string>)));
        Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<,>)));
        Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<,>)));
        Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<string,int>)));
        Console.WriteLine(typeof(Foo<int,string>).Implements(typeof(IFoo<string>)));
     }
  12. -1

    No tiene nada de malo el siguiente:

    bool implementsGeneric = (anObject.Implements("IBar`1") != null);

    Para crédito extra se puede coger AmbiguousMatchException si quería proporcionar un determinado tipo genérico-parámetro con el IBar consulta.

    • Bueno, por lo general es mejor evitar el uso de literales de cadena cuando sea posible. Este enfoque haría más difícil para refactorizar la aplicación, ya que el cambio de nombre de la IBar, la interfaz no cambia el literal de cadena, y el error sólo sería detectable en tiempo de ejecución.
    • Tanto como me suele estar de acuerdo con el comentario anterior sobre el uso de la magia «cuerdas», etc, este es el mejor método que he encontrado. Bueno lo suficientemente cerca – pruebas para la PropertyType.Nombre equivale a «IWhatever`1».
    • ¿Por qué no esta? bool implementsGeneric = (anObject.Implements(typeof(IBar<>).Name) != null);

Dejar respuesta

Please enter your comment!
Please enter your name here