Como faço para verificar se um tipo é um subtipo OU o tipo de um object?

Para verificar se um tipo é uma subclass de outro tipo em C #, é fácil:

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

No entanto, isso falhará:

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

Existe alguma maneira de verificar se um tipo é uma subclass OR da própria class base, sem usar um operador OR ou usando um método de extensão?

Aparentemente, não.

Aqui estão as opções:

  • Use Type.IsSubclassOf
  • Use Type.IsAssignableFrom
  • is e as

Type.IsSubclassOf

Como você já descobriu, isso não funcionará se os dois tipos forem iguais, aqui está uma amostra do programa LINQPad que demonstra:

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

Saída:

 True False 

O que indica que Derived é uma subclass de Base , mas essa Base é (obviamente) uma subclass de si mesma.

Type.IsAssignableFrom

Agora, isso responderá a sua pergunta específica, mas também lhe dará falsos positivos. Como Eric Lippert apontou nos comentários, embora o método realmente retorne True para as duas perguntas acima, ele também retornará True para essas, o que você provavelmente não deseja:

 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 { } 

Aqui você obtém a seguinte saída:

 True True True 

O último True ali indicaria, se o método respondesse apenas a pergunta feita, que uint[] herda de int[] ou que eles são do mesmo tipo, o que claramente não é o caso.

Portanto IsAssignableFrom não é totalmente correto também.

is e as

O “problema” com e is as no contexto da sua pergunta é que eles exigirão que você opere nos objects e escreva um dos tipos diretamente no código, e não trabalhe com os objects Type .

Em outras palavras, isso não compilará:

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

nem isso:

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

nem isso:

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

Conclusão

Embora os methods acima possam atender às suas necessidades, a única resposta correta à sua pergunta (como eu vejo) é que você precisará de uma verificação extra:

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

o que obviamente faz mais sentido em um método:

 public bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant) { return potentialDescendant.IsSubclassOf(potentialBase) || potentialDescendant == potentialBase; } 
 typeof(BaseClass).IsAssignableFrom(unknownType); 

Você deve tentar usar Type.IsAssignableFrom em vez disso.

Se você está tentando fazer isso em um projeto Xamarin Forms PCL, as soluções acima usando IsAssignableFrom apresentam um erro:

Erro: ‘Tipo’ não contém uma definição para ‘IsAssignableFrom’ e nenhum método de extensão ‘IsAssignableFrom’ aceitando um primeiro argumento do tipo ‘Tipo’ pode ser encontrado (você está perdendo uma diretiva usando ou uma referência de assembly?)

porque IsAssignableFrom pede um object TypeInfo . Você pode usar o método GetTypeInfo() de System.Reflection :

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

Estou postando essa resposta com a esperança de que alguém compartilhe comigo se e por que seria uma má ideia. No meu aplicativo, eu tenho uma propriedade do tipo que eu quero verificar para ter certeza de que é typeof (A) ou typeof (B), onde B é qualquer class derivada de A. Então, meu 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; } } } 

Eu sinto que posso ser um pouco ingênuo aqui, então qualquer feedback seria bem-vindo.