Перевірте, чи 'T' успадковує або реалізує клас / інтерфейс


92

Чи є спосіб перевірити, чи успадковує / реалізує клас клас / інтерфейс?

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

4
здається, це працює ... якщо (typeof (TestClass) .IsAssignableFrom (typeof (T))), хтось може підтвердити мої підозри? Дякую!
користувач1229895

Я абсолютно впевнений, що ця відповідь дублюється багато разів!
Фелікс К.

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))
д-р Ендрю Бернетт-Томпсон,

Не зроблено nikeee; стара відповідь все ще є. :) Я взяв пару секунд, щоб зрозуміти, що не так. У будь-якому випадку, +1, приємна особливість знову .NET framework.
Самуель

Насправді, те, як ви згадуєте, - це те, що було у мене деякий час тому. Я виправив цю. Див. Попередні коментарі. T inherits Uнасправді перекладається на typeof(T).IsAssignableFrom(typeof(U)).
nikeee

3
Хоча це майже працює, є проблема, коли, якщо Tобмежується якимось іншим типом TOther, тоді при виконанні typeof(T)фактично буде оцінюватися, typeof(TOther)а не будь-якому типу, який Tви насправді передали, і в такому випадку typeof(SomeInterface).IsAssignableFrom(typeof(T))не вдасться (припускаючи, що TOtherце також не реалізується SomeInterface), навіть якщо ваш конкретний тип реалізував SomeInterface.
Dave Cousineau

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


16

Якщо ви хочете перевірити під час компіляції: Помилка, якщо, якщо 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, або якщо 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;
}

Результати

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

Правда

дитина1-> базовий клас

помилковий

базовий клас-> дитина1

Правда

дитина2-> базовий клас

помилковий

базовий клас-> дитина2

Правда

nobase-> baseclass

помилковий

baseclass-> nobase

помилковий

і

  • ПОМИЛКА: c1 = b1
  • b1 = c1
  • ПОМИЛКА: c2 = b1
  • b1 = c2


0

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


Це працює, якщо тільки SomeClassбезпосередньо не походить від BaseClass.
Suncat2000

0

Альтернативні способи визначити, чи об’єкт oуспадковує клас або реалізує інтерфейс, це використання операторів isand as.

Якщо ви хочете знати лише, чи об’єкт успадковує клас або реалізує інтерфейс, isоператор поверне логічний результат:

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

Якщо ви хочете використовувати успадкований клас або реалізований інтерфейс після тесту, asоператор виконає безпечний привід, повернувши посилання на успадкований клас або реалізований інтерфейс, якщо сумісний або нульовий, якщо не сумісний:

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.