Как проверить, является ли тип подтипом ИЛИ типом объекта?

Чтобы проверить, является ли тип подклассом другого типа в С#, легко:

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

Однако это не сработает:

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

Есть ли способ проверить, является ли тип либо подклассом OR самого базового класса, без использования оператора OR, либо с использованием метода расширения?

Ответ 1

По-видимому, нет.

Здесь варианты:

Type.IsSubclassOf

Как вы уже выяснили, это не сработает, если два типа совпадают, вот пример LINQPad, который демонстрирует:

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

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

Вывод:

True
False

Что означает, что Derived является подклассом Base, но Base (очевидно) не является подклассом самого себя.

Type.IsAssignableFrom

Теперь это ответит на ваш конкретный вопрос, но также даст вам ложные срабатывания. Как отметил Эрик Липперт в комментариях, в то время как метод действительно вернет True для двух вышеуказанных вопросов, он также вернет True для них, чего вы, вероятно, не хотите:

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

Здесь вы получаете следующий вывод:

True
True
True

В последнем True будет указано, будет ли метод отвечать только на заданный вопрос, что uint[] наследует от int[] или что они одного типа, что явно не так.

Так что IsAssignableFrom также не совсем корректно.

is и as

"Проблема" с is и as в контексте вашего вопроса заключается в том, что они потребуют от вас работы с объектами и записи одного из типов непосредственно в коде и не работать с объектами Type.

Другими словами, это не скомпилируется:

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

и не будет:

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

и не будет:

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

Заключение

Хотя приведенные выше методы могут соответствовать вашим потребностям, единственный правильный ответ на ваш вопрос (как я вижу) заключается в том, что вам потребуется дополнительная проверка:

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

что, конечно, имеет смысл в методе:

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

Ответ 2

typeof(BaseClass).IsAssignableFrom(unknownType);

Ответ 3

Вместо этого попробуйте использовать Type.IsAssignableFrom.

Ответ 4

Я отправляю этот ответ с надеждой на то, что кто-то поделится со мной, если и почему это будет плохая идея. В моем приложении у меня есть свойство Type, которое я хочу проверить, чтобы убедиться, что это typeof (A) или typeof (B), где B - любой класс, полученный из A. Таким образом, мой код:

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

Мне кажется, что я немного наивна, поэтому любая обратная связь будет приветствоваться.