¿Cómo puedo comprobar si un tipo es un subtipo O el tipo de un objeto?


Para comprobar si un tipo es una subclase de otro tipo en C#, es fácil:

typeof (SubClass).IsSubclassOf(typeof (BaseClass)); // returns true

Sin embargo, esto fallará:

typeof (BaseClass).IsSubclassOf(typeof (BaseClass)); // returns false

¿Hay alguna manera de comprobar si un tipo es una subclase O de la propia clase base, sin usar un operador OR o usar un método de extensión?

Author: abatishchev, 2010-04-30

5 answers

Aparentemente, no.

Aquí están las opciones:

Tipo.IsSubclassOf

Como ya ha descubierto, esto no funcionará si los dos tipos son los mismos, aquí hay un ejemplo LINQPad programa que demuestra:

void Main()
{
    typeof(Derived).IsSubclassOf(typeof(Base)).Dump();
    typeof(Base).IsSubclassOf(typeof(Base)).Dump();
}

public class Base { }
public class Derived : Base { }

Salida:

True
False

Que indica que Derived es una subclase de Base, pero que Base no es (obviamente) una subclase en sí misma.

Tipo.IsAssignableFrom

Ahora, esto responderá a su pregunta particular, pero también le dará falsos positivos. Como Eric Lippert ha señalado en los comentarios, mientras que el método de hecho devolverá True para las dos preguntas anteriores, también devolverá True para estas, que probablemente no desee:

void Main()
{
    typeof(Base).IsAssignableFrom(typeof(Derived)).Dump();
    typeof(Base).IsAssignableFrom(typeof(Base)).Dump();
    typeof(int[]).IsAssignableFrom(typeof(uint[])).Dump();
}

public class Base { }
public class Derived : Base { }

Aquí se obtiene la siguiente salida:

True
True
True

El último True allí indicaría, si el method solo respondió a la pregunta formulada, que uint[] hereda de int[] o que son del mismo tipo, lo que claramente no es el caso.

Así que IsAssignableFrom tampoco es del todo correcto.

is y as

El "problema" con is y as en el contexto de su pregunta es que requerirán que opere sobre los objetos y escriba uno de los tipos directamente en código, y no trabaje con objetos Type.

En otras palabras, esto no compile:

SubClass is BaseClass
^--+---^
   |
   +-- need object reference here

Tampoco esto: {[26]]}

typeof(SubClass) is typeof(BaseClass)
                    ^-------+-------^
                            |
                            +-- need type name here, not Type object

Tampoco esto: {[26]]}

typeof(SubClass) is BaseClass
^------+-------^
       |
       +-- this returns a Type object, And "System.Type" does not
           inherit from BaseClass

Conclusión

Si bien los métodos anteriores podrían ajustarse a sus necesidades, la única respuesta correcta a su pregunta (como yo la veo) es que necesitará una verificación adicional:

typeof(Derived).IsSubclassOf(typeof(Base)) || typeof(Derived) == typeof(Base);

Que por supuesto tiene más sentido en un método:

public bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant)
{
    return potentialDescendant.IsSubclassOf(potentialBase)
           || potentialDescendant == potentialBase;
}
 409
Author: Lasse Vågsæther Karlsen,
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-07-04 13:42:16
typeof(BaseClass).IsAssignableFrom(unknownType);
 26
Author: Marc Gravell,
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
2010-04-30 04:26:29

Deberías intentar usar el tipo .IsAssignableFrom en su lugar.

 7
Author: Thomas,
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
2010-04-30 04:26:50

Si está intentando hacerlo en un proyecto PCL de Xamarin Forms, las soluciones anteriores que usan IsAssignableFrom dan un error:

Error: 'Type' no contiene una definición para 'IsAssignableFrom' y ningún método de extensión' IsAssignableFrom ' acepta un primer argumento de tipo 'Tipo' se podría encontrar (¿le falta una directiva de uso o un referencia de ensamblado?)

Porque IsAssignableFrom pide un objeto TypeInfo. Puedes usar el método GetTypeInfo() desde System.Reflection:

typeof(BaseClass).GetTypeInfo().IsAssignableFrom(typeof(unknownType).GetTypeInfo())

 1
Author: BrunoSerrano,
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
2018-03-21 13:34:10

Estoy publicando esta respuesta con la esperanza de que alguien comparta conmigo si y por qué sería una mala idea. En mi aplicación, tengo una propiedad de Tipo que quiero comprobar para estar seguro de que es typeof(A) o typeof (B) , donde B es cualquier clase derivada de A. Así que mi código:

public class A
{
}

public class B : A
{
}

public class MyClass
{
    private Type _helperType;
    public Type HelperType
    {
        get { return _helperType; }
        set 
        {
            var testInstance = (A)Activator.CreateInstance(value);
            if (testInstance==null)
                throw new InvalidCastException("HelperType must be derived from A");
            _helperType = value;
        }
    }
}

Siento que podría ser un poco ingenuo aquí, por lo que cualquier comentario sería bienvenido.

 0
Author: baskren,
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
2016-09-12 10:58:42