Periksa apakah 'T' mewarisi atau mengimplementasikan kelas / antarmuka

92

Apakah ada cara untuk menguji apakah T mewarisi / mengimplementasikan kelas / antarmuka?

private void MyGenericClass<T> ()
{
    if(T ... inherits or implements some class/interface
}
pengguna1229895
sumber
4
ini tampaknya berfungsi ... if (typeof (TestClass) .IsAssignableFrom (typeof (T))), dapatkah seseorang mengonfirmasi kecurigaan saya? Terima kasih!
pengguna1229895
Saya yakin sepenuhnya bahwa jawaban ini diduplikasi berkali-kali!
Felix K.
3
Felix K Bahkan jika jawaban ini telah diduplikasi berkali-kali, itu juga membantu banyak orang berkali-kali;) ... seperti saya lima menit yang lalu :)
Samuel

Jawaban:

136

Ada Metode yang disebut Type.IsAssignableFrom () .

Untuk memeriksa apakah Tmewarisi / mengimplementasikan Employee:

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

Jika Anda menargetkan .NET Core, metode telah dipindahkan ke TypeInfo:

typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).Ge‌​tTypeInfo())
nikeee
sumber
Anda harus memperbarui jawaban Anda dengan sebuah contoh, misalnya typeof (T) .IsAssignableFrom (typeof (IMyInterface))
Dr. Andrew Burnett-Thompson
Tidak dilakukan nikeee; jawaban lama masih ada. :) Saya mengambil beberapa detik untuk mencari tahu apa yang salah. Bagaimanapun, +1, fitur bagus lagi dari kerangka kerja .net.
Samuel
Nyatanya, cara Anda menyebutkannya seperti yang saya alami beberapa waktu lalu. Saya mengoreksi yang ini. Lihat komentar sebelumnya. T inherits Usebenarnya diterjemahkan menjadi typeof(T).IsAssignableFrom(typeof(U)).
nikeee
3
Meskipun ini hampir berhasil, ada masalah di mana jika Tdibatasi ke beberapa jenis lain TOther, kemudian ketika dijalankan, typeof(T)akan benar-benar mengevaluasi ke typeof(TOther)dan bukan jenis apa pun yang Tsebenarnya Anda lewati, dan dalam kasus itu, typeof(SomeInterface).IsAssignableFrom(typeof(T))akan gagal (dengan asumsi TOthertidak juga diterapkan SomeInterface), meskipun jenis beton Anda benar-benar diterapkan SomeInterface.
Dave Cousineau
1
Dalam inti .net IsAssignableFromdari TypeInfokelas hanya menerima TypeInfo karena hanya argumen itu, sehingga sampel harus berikut:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
Untuk Ka
16

Jika Anda ingin memeriksa selama kompilasi: Kesalahan jika T TIDAK menerapkan antarmuka / kelas yang diinginkan, Anda dapat menggunakan batasan berikut

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

Saya harap itu membantu.

snajahi
sumber
12

Sintaks yang benar adalah

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

Dokumentasi

Return Value: true jika cdan arus Typemewakili tipe yang sama, atau jika arus Typeberada dalam hierarki pewarisan c, atau jika arus Typeadalah interfaceyang cmengimplementasikan, atau jika cadalah tipe parameter generik dan arus Typemewakili salah satu batasan c, atau jika cmewakili tipe nilai dan arus Typemewakili Nullable<c>( Nullable(Of c)dalam Visual Basic). falsejika tidak ada dari kondisi ini true, atau jika cada null.

sumber

Penjelasan

Jika Employee IsAssignableFrom Tkemudian Tmewarisi dari Employee.

Penggunaan

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

kembali true hanya jika salah satunya

  1. Tdan Employeemewakili tipe yang sama; atau,
  2. Employeemewarisi dari T.

Ini mungkin penggunaan yang dimaksudkan dalam beberapa kasus, tetapi untuk pertanyaan asli (dan penggunaan yang lebih umum), untuk menentukan kapan Tmewarisi atau mengimplementasikan beberapa class/ interface, gunakan:

typeof(Employee).IsAssignableFrom(typeof(T))
Luke
sumber
9

Yang dimaksud setiap orang adalah:

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

karena Anda benar-benar dapat menetapkan dari sebuah contoh DerivedTypeke sebuah contoh dari BaseType:

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

kapan

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

Dan beberapa contoh konkret jika Anda kesulitan membungkus kepala Anda di sekitarnya:

(melalui LinqPad, karenanya HorizontalRundan 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;
}

Hasil

baseclass-> baseclass

Benar

child1-> baseclass

Salah

baseclass-> child1

Benar

child2-> baseclass

Salah

baseclass-> child2

Benar

nobase-> baseclass

Salah

baseclass-> nobase

Salah

dan

  • GAGAL: c1 = b1
  • b1 = c1
  • GAGAL: c2 = b1
  • b1 = c2
drzaus
sumber
2

Saya percaya sintaksnya adalah: typeof(Employee).IsAssignableFrom(typeof(T));

Pucat
sumber
Ini adalah sintaks yang dimaksudkan. +1
Lukas
0

Meskipun IsAssignableFrom adalah cara terbaik seperti yang dinyatakan orang lain, jika Anda hanya perlu memeriksa apakah kelas mewarisi dari kelas lain, typeof(T).BaseType == typeof(SomeClass)lakukan pekerjaan itu juga.

Jed
sumber
Itu berfungsi kecuali SomeClasstidak secara langsung berasal dari BaseClass.
Suncat2000
0

Cara alternatif untuk mengetahui apakah suatu objek omewarisi kelas atau mengimplementasikan antarmuka adalah dengan menggunakan isdanas operator .

Jika Anda hanya ingin mengetahui apakah suatu objek mewarisi kelas atau mengimplementasikan antarmuka, isoperator akan mengembalikan hasil boolean:

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

Jika Anda ingin menggunakan kelas yang diwariskan atau antarmuka yang diimplementasikan setelah pengujian Anda, asoperator akan melakukan transmisi yang aman, mengembalikan referensi ke kelas yang diwariskan atau antarmuka yang diimplementasikan jika kompatibel atau null jika tidak kompatibel:

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.

Jika Anda hanya memiliki tipe T, gunakan jawaban @ nikeee.

Suncat2000
sumber