it-swarm.com.ru

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

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

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

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

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

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

308
Daniel T.

Видимо, нет.

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

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;
}
451
Lasse Vågsæther Karlsen
typeof(BaseClass).IsAssignableFrom(unknownType);
29
Marc Gravell

Вместо этого вы должны попробовать использовать Type.IsAssignableFrom .

8
Thomas

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

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

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

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

1
BrunoSerrano

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

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

0
baskren