Refleksi dan jenis generik

Dari sudut pandang pantulan, perbedaan antara jenis generik dan jenis biasa adalah bahwa jenis generik telah dikaitkan dengannya sekumpulan parameter jenis (jika itu adalah definisi jenis generik) atau argumen jenis (jika itu adalah jenis yang dibangun). Metode generik berbeda dari metode biasa dengan cara yang sama.

Ada dua kunci untuk memahami bagaimana pantulan menangani jenis dan metode generik:

  • Parameter jenis definisi jenis generik dan definisi metode generik diwakili oleh instans kelas Type.

    Catatan

    Banyak properti dan metode Type memiliki perilaku yang berbeda ketika objek Type mewakili parameter jenis generik. Perbedaan ini didokumenkan dalam artikel properti dan metode. Misalnya, lihat IsAutoClass dan DeclaringType. Selain itu, beberapa anggota hanya valid ketika objek Type mewakili parameter jenis generik. Misalnya, lihat GetGenericTypeDefinition.

  • Jika instans Type mewakili jenis generik, maka instans tersebut menyertakan array jenis yang mewakili parameter jenis (untuk definisi jenis generik) atau argumen jenis (untuk jenis yang dibangun). Hal yang sama berlaku untuk instans kelas MethodInfo yang mewakili metode generik.

Reflection menyediakan metode Type dan MethodInfo yang memungkinkan Anda mengakses array parameter jenis, dan untuk menentukan apakah instans Type mewakili parameter jenis atau jenis aktual.

Misalnya kode yang menunjukkan metode yang dibahas di sini, lihat Cara: Memeriksa dan Membuat Instans Jenis Generik dengan Refleksi.

Diskusi berikut mengasumsikan keakraban dengan terminologi generik, seperti perbedaan antara parameter jenis dan argumen dan jenis yang dibangun terbuka atau tertutup. Untuk informasi selengkapnya, lihat Generik.

Apakah ini jenis atau metode generik?

Saat Anda menggunakan pantulan untuk memeriksa jenis yang tidak diketahui, yang diwakili oleh instans Type, gunakan properti IsGenericType untuk menentukan apakah jenis yang tidak diketahui bersifat generik. Ini mengembalikan true jika jenisnya generik. Demikian pula, ketika Anda memeriksa metode yang tidak diketahui, yang diwakili oleh instans kelas MethodInfo, gunakan properti IsGenericMethod untuk menentukan apakah metode tersebut generik.

Apakah ini jenis generik atau definisi metode?

Gunakan properti IsGenericTypeDefinition untuk menentukan apakah objek Type mewakili definisi jenis generik, dan gunakan metode IsGenericMethodDefinition untuk menentukan apakah MethodInfo mewakili definisi metode generik.

Jenis generik dan definisi metode adalah templat dari mana jenis yang dapat digunakan dibuat. Jenis generik dalam pustaka .NET, seperti Dictionary<TKey,TValue>, adalah definisi jenis generik.

Apakah jenis atau metode terbuka atau tertutup?

Jenis atau metode generik ditutup jika jenis yang dapat digunakan telah diganti untuk semua parameter jenisnya, termasuk semua parameter jenis dari semua jenis yang mencakup. Anda hanya dapat membuat instans jenis generik jika ditutup. Properti Type.ContainsGenericParameters mengembalikan true jika suatu jenis terbuka. Untuk metode, metode MethodBase.ContainsGenericParameters melakukan fungsi yang sama.

Hasilkan jenis generik tertutup

Setelah Anda memiliki jenis generik atau definisi metode, gunakan metode MakeGenericType untuk membuat jenis generik tertutup atau metode MakeGenericMethod untuk membuat MethodInfo untuk metode generik tertutup.

Mendapatkan jenis generik atau definisi metode

Jika Anda memiliki jenis atau metode generik terbuka yang bukan jenis generik atau definisi metode, Anda tidak dapat membuat instansnya dan Anda tidak dapat menyediakan parameter jenis yang hilang. Anda harus memiliki definisi jenis atau metode generik. Gunakan metode GetGenericTypeDefinition untuk mendapatkan definisi jenis generik atau metode GetGenericMethodDefinition untuk mendapatkan definisi metode generik.

Misalnya, jika Anda memiliki objek yang Type mewakili Dictionary<int, string> dan Anda ingin membuat jenis Dictionary<string, MyClass>, Anda dapat menggunakan GetGenericTypeDefinition metode untuk mendapatkan Type representasi Dictionary<TKey, TValue> dan kemudian menggunakan MakeGenericType metode untuk menghasilkan Type representasi Dictionary<int, MyClass>.

Untuk contoh jenis generik terbuka yang bukan jenis generik, lihat Parameter jenis atau argumen jenis.

Memeriksa argumen jenis dan parameter jenis

Gunakan metode Type.GetGenericArguments untuk mendapatkan array objek Type yang mewakili parameter jenis atau argumen jenis dari jenis generik, dan gunakan metode MethodInfo.GetGenericArguments untuk melakukan hal yang sama untuk metode generik.

Setelah Anda tahu bahwa objek Type mewakili parameter jenis, ada banyak refleksi pertanyaan tambahan yang dapat dijawab. Anda dapat menentukan sumber parameter jenis, posisinya, dan batasannya.

Ketik parameter atau ketik argumen

Untuk menentukan apakah elemen tertentu dari array adalah parameter jenis atau argumen jenis, gunakan properti IsGenericParameter. Properti IsGenericParameter adalah true jika elemen merupakan parameter jenis.

Jenis generik dapat terbuka tanpa menjadi definisi jenis generik, dalam hal ini memiliki campuran argumen jenis dan parameter jenis. Misalnya, dalam kode berikut, kelas D berasal dari jenis yang dibuat dengan mengganti parameter D jenis pertama untuk parameter jenis kedua dari B.

class B<T, U> {}
class D<V, W> : B<int, V> {}
Class B(Of T, U)
End Class
Class D(Of V, W)
    Inherits B(Of Integer, V)
End Class
generic<typename T, typename U> ref class B {};
generic<typename V, typename W> ref class D : B<int, V> {};

Jika Anda mendapatkan objek yang Type mewakili dan menggunakan BaseType properti untuk mendapatkan jenis dasarnya, hasilnya type B<int, V> terbuka, tetapi bukan definisi D<V, W> jenis generik.

Sumber parameter generik

Parameter jenis generik mungkin berasal dari jenis yang Anda periksa, dari jenis lampiran, atau dari metode generik. Anda dapat menentukan sumber parameter jenis generik sebagai berikut:

  • Pertama, gunakan properti DeclaringMethod untuk menentukan apakah parameter jenis berasal dari metode generik. Jika nilai properti bukan referensi null, maka sumbernya adalah metode generik.
  • Jika sumbernya bukan merupakan metode generik, gunakan properti DeclaringType untuk menentukan jenis generik yang dimiliki parameter jenis generik.

Jika parameter jenis milik metode generik, properti DeclaringType mengembalikan jenis yang mendeklarasikan metode generik, yang mana tidak relevan.

Posisi parameter generik

Dalam situasi yang jarang terjadi, perlu untuk menentukan posisi parameter jenis dalam daftar parameter jenis kelas deklarasikannya. Misalnya, Anda memiliki objek Type yang mewakili jenis B<int, V> dari contoh sebelumnya. Metode GetGenericArguments memberi Anda daftar argumen jenis, dan ketika Anda memeriksa V Anda dapat menggunakan properti DeclaringMethod dan DeclaringType untuk menemukan dari mana asalnya. Anda kemudian dapat menggunakan properti GenericParameterPosition untuk menentukan posisinya dalam daftar parameter jenis tempat properti ditentukan. Dalam contoh ini, V berada pada posisi 0 (nol) dalam daftar parameter jenis tempat parameter ditentukan.

Jenis dasar dan batasan antarmuka

Gunakan metode GetGenericParameterConstraints untuk mendapatkan batasan jenis dasar dan batasan antarmuka dari parameter jenis. Urutan elemen array tidak signifikan. Elemen mewakili batasan antarmuka jika merupakan jenis antarmuka.

Atribut parameter generik

Properti GenericParameterAttributes mendapatkan nilai GenericParameterAttributes yang menunjukkan varians (kovarians atau kontravarians) dan batasan khusus dari parameter jenis.

Kovarian dan kontravarian

Untuk menentukan apakah parameter merupakan jenis kovarian atau kontravarian, terapkan masker GenericParameterAttributes.VarianceMask ke nilai GenericParameterAttributes yang dikembalikan oleh properti GenericParameterAttributes. Jika hasilnya adalah GenericParameterAttributes.None, parameter jenis merupakan invariant. Untuk informasi selengkapnya, lihat Kovarian dan Kontravarian.

Batasan khusus

Untuk menentukan batasan khusus dari parameter jenis, terapkan masker GenericParameterAttributes.SpecialConstraintMask ke nilai GenericParameterAttributes yang dikembalikan oleh properti GenericParameterAttributes. Jika hasilnya adalah GenericParameterAttributes.None, tidak ada batasan khusus. Parameter jenis dapat dibatasi untuk menjadi jenis referensi, menjadi jenis nilai yang tidak dapat diubah ke null, dan memiliki konstruktor tanpa parameter.

Invarian

Untuk tabel kondisi invarian untuk istilah umum dalam refleksi untuk jenis generik, lihat Type.IsGenericType. Untuk istilah tambahan yang berkaitan dengan metode generik, lihat MethodBase.IsGenericMethod.