Averiguar si un tipo implementa una interfaz genérica


Digamos que tengo un tipo, MyType. Quiero hacer lo siguiente:

  1. Averigüe si MyType implementa la interfaz IList, para algunos T.
  2. Si la respuesta a (1) es sí, averigüe qué es T.

Parece que la forma de hacer esto es GetInterface(), pero eso solo te permite buscar por un nombre específico. ¿Hay una manera de buscar "todas las interfaces que son de la forma IList" (Si es posible también sería útil si funcionó si la interfaz era una subinterfaz de IList.)

Relacionado: Cómo determinar si un tipo implementa un tipo de interfaz genérico específico

Author: Community, 2009-07-14

7 answers

// this conditional is necessary if myType can be an interface,
// because an interface doesn't implement itself: for example,
// typeof (IList<int>).GetInterfaces () does not contain IList<int>!
if (myType.IsInterface && myType.IsGenericType && 
    myType.GetGenericTypeDefinition () == typeof (IList<>))
    return myType.GetGenericArguments ()[0] ;

foreach (var i in myType.GetInterfaces ())
    if (i.IsGenericType && i.GetGenericTypeDefinition () == typeof (IList<>))
        return i.GetGenericArguments ()[0] ;

Edit: Incluso si myType implementa IDerivedFromList<> pero no directamente IList<>, IList<> se muestran en la matriz devuelta por GetInterfaces().

Actualización: se agregó una comprobación para el caso de borde donde myType es la interfaz genérica en cuestión.

 81
Author: Anton Tykhyy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-18 13:00:16

Usando reflexión (y algunos LINQ) puedes hacer esto fácilmente:

public static IEnumerable<Type> GetIListTypeParameters(Type type)
{
    // Query.
    return
        from interfaceType in type.GetInterfaces()
        where interfaceType.IsGenericType
        let baseInterface = interfaceType.GetGenericTypeDefinition()
        where baseInterface == typeof(IList<>)
        select interfaceType.GetGenericArguments().First();
}

Primero, obtiene las interfaces en el tipo y filtra solo para aquellos que son un tipo genérico.

Luego, obtienes la definición de tipo genérico para esos tipos de interfaz, y ves si es lo mismo que IList<>.

A partir de ahí, es una simple cuestión de obtener los argumentos genéricos para la interfaz original.

Recuerde, un tipo puede tener múltiples implementaciones IList<T>, por lo que la IEnumerable<Type> se devuelve.

 11
Author: casperOne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-13 20:40:48
    public static bool Implements<I>(this Type type) where I : class
    {
         if (!typeof(I).IsInterface)
         {
             throw new ArgumentException("Only interfaces can be 'implemented'.");
         }

         return typeof(I).IsAssignableFrom(type);
    }
 4
Author: user989279,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-11 10:19:15

Como extensión de método auxiliar

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!
 1
Author: GenericProgrammer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-24 01:49:32

Usando la propuesta de Anton Tykhyy, aquí hay un pequeño método de extensión para verificar si algún tipo implementa una interfaz genérica con un parámetro de tipo genérico dado:

public static class ExtensionMethods
{
    /// <summary>
    /// Checks if a type has a generic interface. 
    /// For example 
    ///     mytype.HasGenericInterface(typeof(IList<>), typeof(int)) 
    /// will return TRUE if mytype implements IList<int>
    /// </summary>
    public static bool HasGenericInterface(this Type type, Type interf, Type typeparameter)
    {
        foreach (Type i in type.GetInterfaces())
            if (i.IsGenericType && i.GetGenericTypeDefinition() == interf)
                if (i.GetGenericArguments()[0] == typeparameter)
                    return true;

        return false;
    }
}
 1
Author: Knasterbax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-17 14:13:07
Type[] typeArray2 = c.GetInterfaces();
for (int num2 = 0; num2 < typeArray2.Length; num2++)
{
     if (this == typeArray2[num2])
     {
          return true;
     }
}

--http://www.hanselman.com/blog/DoesATypeImplementAnInterface.aspx

 0
Author: Chris Ballance,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-13 20:31:42

Si entiendo su pregunta correctamente, esto es lo que está tratando de hacer. De no ser así, por favor explique más.

public class MyType : ISomeInterface
{
}

MyType o = new MyType();

if(o is ISomeInterface)
 {
 }

Editar: si cambia su pregunta, agregue el hecho de que editó..porque ahora mi respuesta parece que no pertenece.

En ese caso, aquí hay un LINQ

            var item = typeof(MyType).GetInterfaces()
                            .Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IList<>))
                            .Select(t => t.GetGenericArguments().First())
                            .FirstOrDefault();

if( item != null )
 //it has a type
 0
Author: Stan R.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-13 20:54:12