Как проверить, является ли тип подтипом ИЛИ типом объекта? - PullRequest
308 голосов
/ 30 апреля 2010

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

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

Однако это не удастся:

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

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

Ответы [ 5 ]

452 голосов
/ 30 апреля 2010

Видимо, нет.

Вот варианты:

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;
}
29 голосов
/ 30 апреля 2010
typeof(BaseClass).IsAssignableFrom(unknownType);
8 голосов
/ 30 апреля 2010

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

1 голос
/ 21 марта 2018

Если вы пытаетесь сделать это в проекте Xamarin Forms PCL, приведенные выше решения с использованием IsAssignableFrom выдают ошибку:

Ошибка: «Тип» не содержит определения для «IsAssignableFrom» и нет метода расширения IsAssignableFrom, принимающего первый аргумент Тип «Тип» может быть найден (вы пропустили директиву using или ссылка на сборку?)

потому что IsAssignableFrom запрашивает объект TypeInfo. Вы можете использовать метод GetTypeInfo() из System.Reflection:

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

0 голосов
/ 12 сентября 2016

Я публикую этот ответ с надеждой, что кто-то поделится со мной, если и почему это будет плохой идеей. В моем приложении у меня есть свойство 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;
        }
    }
}

Я чувствую, что могу быть немного наивным, поэтому любые отзывы приветствуются.

...