Проверьте, наследует ли 'T' или реализует класс / интерфейс


92

Есть ли способ проверить, наследует ли T / реализует класс / интерфейс?

private void MyGenericClass<T> ()
{
    if(T ... inherits or implements some class/interface
}

4
похоже, это работает ... if (typeof (TestClass) .IsAssignableFrom (typeof (T))), может ли кто-нибудь подтвердить мои подозрения? Благодарность!
user1229895

Абсолютно уверен, что этот ответ повторяется много раз!
Феликс К.

3
Феликс К. Даже если этот ответ дублировался много раз, он также помогает многим парням много раз;) ... как и я пять минут назад :)
Самуэль

Ответы:


136

Существует метод под названием Type.IsAssignableFrom () .

Чтобы проверить, Tнаследует ли / реализует Employee:

typeof(Employee).IsAssignableFrom(typeof(T));

Если вы ориентируетесь на .NET Core, метод перемещен в TypeInfo:

typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).Ge‌​tTypeInfo())

вам следует обновить свой ответ примером, например, typeof (T) .IsAssignableFrom (typeof (IMyInterface))
доктор Эндрю Бернетт-Томпсон,

Не сделано никеее; старый ответ все еще существует. :) Мне потребовалась пара секунд, чтобы разобраться, в чем дело. В любом случае, +1, опять же хорошая особенность .net framework.
Самуэль

Фактически, вы упомянули, как это было у меня некоторое время назад. Я исправил это. См. Предыдущие комментарии. T inherits Uфактически переводится как typeof(T).IsAssignableFrom(typeof(U)).
nikeee

3
Хотя это почти работает, существует проблема, когда if Tограничен каким-то другим типом TOther, а затем при выполнении typeof(T)будет фактически оценивать, typeof(TOther)а не тот тип, который Tвы фактически передали, и в этом случае typeof(SomeInterface).IsAssignableFrom(typeof(T))произойдет сбой (при условии, TOtherчто также не реализуется SomeInterface), даже если ваш конкретный тип реализован SomeInterface.
Дэйв Кузино,

1
В .net сердцевины IsAssignableFromиз TypeInfoкласса принимает только TypeInfo , поскольку это единственный аргумент, так что образец должен быть следующим:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
Для Ka


16

Если вы хотите проверить во время компиляции: Ошибка, если if T НЕ реализует желаемый интерфейс / класс, вы можете использовать следующее ограничение

public void MyRestrictedMethod<T>() where T : MyInterface1, MyInterface2, MySuperClass
{
    //Code of my method here, clean without any check for type constraints.
}

Надеюсь, это поможет.


12

Правильный синтаксис

typeof(Employee).IsAssignableFrom(typeof(T))

Документация

Возвращаемое значение: true если cи ток Typeпредставляет собой один и тот же тип, или если ток Typeнаходится в иерархии наследования c, или если ток Typeявляется , interfaceчто cорудия, или если cэто общий параметр типа и ток Typeпредставляет собой одно из ограничений c, или if cпредставляет тип значения, а текущий Typeпредставляет Nullable<c>( Nullable(Of c)в Visual Basic). falseесли ни одно из этих условий не выполнено trueили cесть null.

источник

Объяснение

Если Employee IsAssignableFrom Tтогда Tнаследуется от Employee.

Использование

typeof(T).IsAssignableFrom(typeof(Employee)) 

возвращается true только когда либо

  1. Tи Employeeпредставляют собой однотипные; или,
  2. Employeeнаследуется от T.

В некоторых случаях это может быть предполагаемое использование , но для исходного вопроса (и более распространенного использования), чтобы определить, когда Tнаследует или реализует некоторые class/ interface, используйте:

typeof(Employee).IsAssignableFrom(typeof(T))

9

На самом деле все имеют в виду:

typeof(BaseType).IsAssignableFrom(typeof(DerivedType)) // => true

потому что вы можете буквально назначить экземпляр a DerivedTypeэкземпляру a BaseType:

DerivedType childInstance = new DerivedType();
BaseType parentInstance = childInstance; // okay, assigning base from derived
childInstance = (DerivedType) parentInstance; // not okay, assigning derived from base

когда

public class BaseType {}
public class DerivedType : BaseType {}

И несколько конкретных примеров, если вам сложно понять это:

(через LinqPad, отсюда HorizontalRunи Dump)

void Main()
{
    // http://stackoverflow.com/questions/10718364/check-if-t-inherits-or-implements-a-class-interface

    var b1 = new BaseClass1();

    var c1 = new ChildClass1();
    var c2 = new ChildClass2();
    var nb = new nobase();

    Util.HorizontalRun(
        "baseclass->baseclass,child1->baseclass,baseclass->child1,child2->baseclass,baseclass->child2,nobase->baseclass,baseclass->nobase",
        b1.IsAssignableFrom(typeof(BaseClass1)),
        c1.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(ChildClass1)),
        c2.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(ChildClass2)),
        nb.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(nobase))
        ).Dump("Results");

    var results = new List<string>();
    string test;

    test = "c1 = b1";
    try {
        c1 = (ChildClass1) b1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "b1 = c1";
    try {
        b1 = c1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "c2 = b1";
    try {
        c2 = (ChildClass2) b1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "b1 = c2";
    try {
        b1 = c2;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    results.Dump();
}

// Define other methods and classes here
public static class exts {
    public static bool IsAssignableFrom<T>(this T entity, Type baseType) {
        return typeof(T).IsAssignableFrom(baseType);
    }
}


class BaseClass1 {
    public int id;
}

class ChildClass1 : BaseClass1 {
    public string name;
}

class ChildClass2 : ChildClass1 {
    public string descr;
}

class nobase {
    public int id;
    public string name;
    public string descr;
}

Полученные результаты

базовый класс-> базовый класс

Правда

child1-> базовый класс

Ложь

базовый класс-> ребенок1

Правда

child2-> базовый класс

Ложь

базовый класс-> ребенок2

Правда

nobase-> базовый класс

Ложь

базовый класс-> nobase

Ложь

а также

  • НЕИСПРАВНОСТЬ: c1 = b1
  • b1 = c1
  • НЕИСПРАВНОСТЬ: c2 = b1
  • b1 = c2


0

Хотя IsAssignableFrom - лучший способ, как заявляли другие, если вам нужно только проверить, наследуется ли класс от другого, typeof(T).BaseType == typeof(SomeClass)тоже выполняет свою работу.


Это работает, если не SomeClassявляется прямым производным от BaseClass.
Suncat2000

0

Альтернативные способы сказать , если объект oнаследует класс или реализует интерфейс для использования isи asоператоров.

Если вы хотите знать, наследует ли объект класс или реализует интерфейс, isоператор вернет логический результат:

bool isCompatibleType = (o is BaseType || o is IInterface);

Если вы хотите использовать унаследованный класс или реализованный интерфейс после теста, asоператор выполнит безопасное преобразование, возвращая ссылку на унаследованный класс или реализованный интерфейс, если он совместим, или null, если он несовместим:

BaseType b = o as BaseType; // Null if d does not inherit from BaseType.

IInterface i = o as IInterface; // Null if d does not implement IInterface.

Если у вас есть только тип T, используйте ответ @nikeee.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.