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

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

Sin embargo, esto se producirá:

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

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

InformationsquelleAutor Daniel T. | 2010-04-30

5 Comentarios

  1. 459

    Al parecer, no.

    Aquí las opciones:

    Tipo.IsSubclassOf

    Como ya has comprobado, esto no va a funcionar si los dos tipos son el mismo, aquí se muestra un ejemplo de LINQPad programa que se muestra:

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

    De salida:

    True
    False

    Que indica que Derived es una subclase de Base, pero que Basees (obviamente) no es una subclase de la misma.

    Tipo.IsAssignableFrom

    Ahora, que esto conteste tu pregunta en particular, sino que también le dan falsos positivos. Como Eric Lippert ha señalado en los comentarios, mientras que el método de hecho va a volver True para las dos preguntas anteriores, también regresará True para estos, que probablemente no quieres:

    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 el siguiente resultado:

    True
    True
    True

    La última True no indicaría, si el método sólo respondió a la pregunta, que uint[] hereda de int[] o que son del mismo tipo, que claramente no es el caso.

    Así IsAssignableFrom no es del todo correcto.

    is y as

    El «problema» con is y as en el contexto de tu pregunta es que se requieren para operar sobre los objetos y escribe uno de los tipos directamente en el código, y no funciona con Type objetos.

    En otras palabras, esto no compilará:

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

    ni tampoco esta:

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

    ni tampoco esta:

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

    Conclusión

    Mientras que los métodos anteriores pueden ajustarse a sus necesidades, la única respuesta correcta a su pregunta (como yo lo veo) es que va a necesitar un extra de verificación:

    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;
    }
    • Gracias! Voy a marcar esto como la respuesta correcta (tengo que esperar 8 minutos más) ya que usted menciona que el cheque tiene que ser revertido y proporciona un enlace a la documentación de MSDN.
    • Tenga en cuenta que esta realidad no hace lo que la pregunta de; esto no determina si una clase es una subclase de otra, sino más bien si un tipo es la asignación compatible con otra. Una matriz de uint no es una subclase de array de int, pero son de asignación compatible. IEnumerable<Jirafa> no es una subclase de IEnumerable<Animal>, pero son de asignación compatible en v4.
    • Gracias Eric, bueno a tener en cuenta.
    • Dispara, yo no creo de que, gracias Eric!
    • No hay manera de hacer esto en nombre de método como Java? « void <? se extiende de la Base> saveObject(? objectToSave)«
    • ¿Cómo IsInstanceOfType ajuste en esto?
    • Puede ser tentador para convertir IsSameOrSubclass en un método de extensión, pero yo recomiendo en contra de ella, es un poco incómodo de leer y escribir, y fácil de desastre (invirtiendo el orden de potentialBase y potentialDescendant puede ser mortal).

  2. 1

    Si usted está tratando de hacerlo en un Xamarin Forms PCL proyecto, las soluciones anteriores utilizando IsAssignableFrom da un error:

    Error: ‘Tipo’ no contiene una definición para ‘IsAssignableFrom’ y
    ningún método de extensión ‘IsAssignableFrom’ aceptar un primer argumento de
    tipo ‘tipo’ podría ser encontrado (¿falta una directiva using o una
    referencia de ensamblado?)

    porque IsAssignableFrom pide un TypeInfo objeto.
    Usted puede utilizar el GetTypeInfo() método de System.Reflection:

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

  3. 0

    Estoy publicando esta respuesta con la esperanza de que alguien que comparte conmigo si y por qué sería una mala idea. En mi aplicación tengo una propiedad de Tipo que desea comprobar para asegurarse de que está 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;
            }
        }
    }

    Me siento como que podría ser un poco ingenuo aquí, así que cualquier opinión será bienvenida.

    • Hay un par de problemas con la idea de que: 1) el tipo de necesidades de un constructor sin parámetros o CreateInstance fallará; 2) fundición (a) no devuelve null si el reparto no puede ser hecho, lanza; 3) que en realidad no necesita a la nueva instancia, por lo que tiene un inútil asignación. El aceptó respuesta es mejor (aunque no perfecto).
    • Gracias por los comentarios. Muy útil.

Dejar respuesta

Please enter your comment!
Please enter your name here