Saya memiliki kelas generik dalam proyek saya dengan kelas turunan.
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
Apakah ada cara untuk mengetahui apakah suatu Type
objek berasal GenericClass
?
t.IsSubclassOf(typeof(GenericClass<>))
tidak bekerja.
c#
generics
reflection
bernhardrusch
sumber
sumber
(Diposting ulang karena penulisan ulang besar-besaran)
Jawaban kode JaredPar luar biasa, tapi saya punya tip yang akan membuatnya tidak perlu jika tipe generik Anda tidak didasarkan pada parameter tipe nilai. Saya terpaku pada alasan operator "is" tidak bekerja, jadi saya juga mendokumentasikan hasil eksperimen saya untuk referensi di masa mendatang. Harap tingkatkan jawaban ini untuk lebih meningkatkan kejelasannya.
TIP:
Jika Anda memastikan bahwa implementasi GenericClass Anda mewarisi dari kelas dasar non-generik abstrak seperti GenericClassBase, Anda dapat mengajukan pertanyaan yang sama tanpa masalah sama sekali seperti ini:
IsSubclassOf ()
Pengujian saya menunjukkan bahwa IsSubclassOf () tidak berfungsi pada tipe generik tanpa parameter seperti
sedangkan itu akan bekerja dengan
Karenanya kode berikut ini akan berfungsi untuk turunan apa pun dari GenericClass <>, dengan asumsi Anda bersedia menguji berdasarkan SomeType:
Satu-satunya waktu saya dapat membayangkan bahwa Anda ingin menguji oleh GenericClass <> adalah dalam skenario plug-in framework.
Pikiran tentang operator "adalah"
Pada waktu-desain, C # tidak mengizinkan penggunaan generik tanpa parameter karena pada dasarnya mereka bukan tipe CLR yang lengkap. Oleh karena itu, Anda harus mendeklarasikan variabel generik dengan parameter, dan itulah sebabnya operator "is" begitu kuat untuk bekerja dengan objek. Kebetulan, operator "adalah" juga tidak dapat mengevaluasi tipe generik tanpa parameter.
Operator "is" akan menguji seluruh rantai pewarisan, termasuk antarmuka.
Jadi, dengan memberi instance objek apa pun, metode berikut akan melakukan trik:
Ini agak berlebihan, tetapi saya pikir saya akan melanjutkan dan memvisualisasikannya untuk semua orang.
Diberikan
Baris kode berikut akan mengembalikan true:
Di sisi lain, jika Anda menginginkan sesuatu yang spesifik untuk GenericClass, Anda dapat membuatnya lebih spesifik, saya kira, seperti ini:
Maka Anda akan menguji seperti ini:
sumber
Type
objek.typeof
operator. Menurut dokumen: "Operator typeof digunakan untuk mendapatkan objek System.Type untuk jenis."Saya bekerja melalui beberapa sampel ini dan menemukan mereka kurang dalam beberapa kasus. Versi ini berfungsi dengan semua jenis obat generik: tipe, antarmuka, dan definisi tipe.
Berikut adalah unit test juga:
sumber
!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent;
Jadi, Anda mengganti variabel itu dengan perluasan pernyataan if:if (parent.IsGenericType && shouldUseGenericType)
dan Anda dapatkanif (parent.IsGenericType && (!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent))
yang kemudian mengurangi menjadiif (parent.IsGenericType && parent.GetGenericTypeDefinition() == parent)) parent = parent.GetGenericTypeDefinition();
int j = 0;
if (j is an int && j == 0)
{ j=0; }
Apakah saya mendapatkan referensi saya sama dan nilai sama dengan tercampur? Saya pikir hanya ada satu contoh dari masing-masing jenis dalam memori, jadi dua variabel yang menunjuk ke jenis yang sama sebenarnya menunjuk ke lokasi yang sama di memori.Tampaknya bagi saya bahwa implementasi ini berfungsi dalam lebih banyak kasus (kelas umum dan antarmuka dengan atau tanpa parameter yang diinisiasi, terlepas dari jumlah anak dan parameter):
Berikut adalah
7076 kasus pengujian saya:Kelas dan antarmuka untuk pengujian:
sumber
Kode JaredPar berfungsi tetapi hanya untuk satu tingkat warisan. Untuk tingkat warisan yang tidak terbatas, gunakan kode berikut
sumber
while
dalam JaredPar mencakup level yang tidak terbatas.Berikut adalah sedikit metode yang saya buat untuk memeriksa bahwa suatu objek diturunkan dari tipe tertentu. Bekerja sangat bagus untuk saya!
sumber
Mungkin berlebihan tetapi saya menggunakan metode ekstensi seperti berikut ini. Mereka memeriksa antarmuka serta subkelas. Itu juga dapat mengembalikan tipe yang memiliki definisi generik yang ditentukan.
Misalnya untuk contoh dalam pertanyaan itu dapat menguji terhadap antarmuka generik serta kelas generik. Tipe yang dikembalikan dapat digunakan dengan
GetGenericArguments
untuk menentukan bahwa tipe argumen generik adalah "SomeType".sumber
Membangun jawaban yang sangat baik di atas oleh fir3rpho3nixx dan David Schmitt, saya telah memodifikasi kode mereka dan menambahkan tes ShouldInheritOrImplementTypedGenericInterface (yang terakhir).
sumber
Ini semua bisa dilakukan dengan mudah dengan LINQ. Ini akan menemukan semua jenis yang merupakan subkelas dari GenericBaseType kelas dasar generik.
sumber
Solusi sederhana: cukup buat dan tambahkan antarmuka non-generik kedua ke kelas generik:
Kemudian hanya memeriksa bahwa dalam cara apapun yang Anda suka menggunakan
is
,as
,IsAssignableFrom
, dllJelas hanya mungkin jika Anda memiliki kemampuan untuk mengedit kelas generik (yang tampaknya dimiliki OP), tetapi ini sedikit lebih elegan dan mudah dibaca daripada menggunakan metode ekstensi kriptik.
sumber
IGenericClass
tidak akan menjamin Anda bahwaGenericClass
atauGenericInterface
benar-benar diperpanjang atau diterapkan. Ini berarti, kompiler Anda juga tidak akan memungkinkan Anda untuk mengakses anggota kelas generik mana pun.Ditambahkan ke jawaban @ jaredpar, inilah yang saya gunakan untuk memeriksa antarmuka:
Ex:
sumber
JaredPar,
Ini tidak berfungsi untuk saya jika saya melewatkan typeof (ketik <>) sebagai toCheck. Inilah yang saya ubah.
sumber
typeof(type<>)
sebagaitoCheck
. Anda juga benar-benar membutuhkan cek nol seperti pada solusi JaredPar. Selain itu, saya tidak tahu apa lagi yang Anda capai dengan mengganticur == generic
solusinya dengancur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()
selain membatasi metode Anda untuk bekerja hanya untuk tipe generik. Dengan kata lain, hal seperti ini gagal dengan pengecualian:IsSubclassOfRawGeneric(typeof(MyClass), typeof(MyClass<>))
@EnocNRoll - Jawaban Ananda Gopal menarik, tetapi jika sebuah instance tidak dipakai sebelumnya atau Anda ingin memeriksa dengan definisi tipe generik, saya akan menyarankan metode ini:
dan gunakan seperti:
Ada empat kasus bersyarat ketika keduanya
t
(akan diuji) dand
merupakan tipe generik dan dua kasus dicakup oleht==d
yang (1) tidakt
jugad
merupakan definisi generik atau (2) keduanya merupakan definisi generik . Kasus sisanya adalah salah satunya adalah definisi generik, hanya ketikad
sudah definisi generik kita memiliki kesempatan untuk mengatakan at
adalahd
tetapi tidak sebaliknya.Ini harus bekerja dengan kelas atau antarmuka yang sewenang-wenang yang ingin Anda uji, dan mengembalikan apa yang seolah-olah Anda uji instance dari tipe itu dengan
is
operator.sumber
sumber
Anda dapat mencoba ekstensi ini
sumber
terlambat ke permainan pada ini ... saya juga belum permutasi lain dari jawaban JarodPar.
inilah Type.IsSubClassOf (Type) milik reflektor:
dari itu, kita melihat bahwa itu tidak melakukan apa-apa juga cray cray dan mirip dengan pendekatan berulang JaredPar. sejauh ini baik. inilah versi saya (penafian: tidak diuji secara menyeluruh, jadi saya tahu jika Anda menemukan masalah)
pada dasarnya ini hanyalah metode ekstensi untuk System.Type - saya melakukan ini dengan sengaja membatasi Tipe "thisType" untuk Jenis beton, karena penggunaan langsung saya adalah untuk permintaan LINQ "di mana" predikat terhadap objek Jenis. saya yakin semua orang pintar di luar sana dapat menggedornya menjadi metode statis serba guna yang efisien jika Anda perlu :) kode melakukan beberapa hal kode jawaban tidak
sisanya pada dasarnya sama dengan kode JaredPar
sumber