Pertanyaan berdasarkan contoh MSDN .
Katakanlah kita memiliki beberapa kelas C # dengan HelpAttribute di aplikasi desktop mandiri. Apakah mungkin untuk menghitung semua kelas dengan atribut seperti itu? Apakah masuk akal untuk mengenali kelas dengan cara ini? Atribut khusus akan digunakan untuk membuat daftar opsi menu yang mungkin, memilih item akan membawa ke instance layar kelas tersebut. Jumlah kelas / item akan tumbuh lambat, tetapi dengan cara ini kita dapat menghindari penghitungan semuanya di tempat lain, saya pikir.
Select
metode ekstensi, dan kompiler akan menghasilkan mesin negara seperti halnya jika Anda meneleponSelect
karena penggunaan Andayield return
. Akhirnya, setiap perolehan kinerja yang mungkin diperoleh dalam sebagian besar kasus adalah optimasi mikro.Nah, Anda harus menghitung melalui semua kelas di semua majelis yang dimuat ke domain aplikasi saat ini. Untuk melakukan itu, Anda akan memanggil
GetAssemblies
metode padaAppDomain
contoh untuk domain aplikasi saat ini.Dari sana, Anda akan menelepon
GetExportedTypes
(jika Anda hanya ingin tipe publik) atauGetTypes
masingAssembly
- masing untuk mendapatkan tipe yang terkandung dalam majelis.Kemudian, Anda akan memanggil
GetCustomAttributes
metode ekstensi pada setiapType
instance, melewati tipe atribut yang ingin Anda temukan.Anda dapat menggunakan LINQ untuk menyederhanakan ini untuk Anda:
Kueri di atas akan memberi Anda setiap jenis dengan atribut yang diterapkan padanya, bersama dengan instance atribut yang ditugaskan padanya.
Perhatikan bahwa jika Anda memiliki banyak rakitan yang dimuat ke domain aplikasi Anda, operasi itu bisa mahal. Anda dapat menggunakan LINQ Paralel untuk mengurangi waktu operasi, seperti:
Memfilternya pada spesifik
Assembly
adalah sederhana:Dan jika perakitan memiliki sejumlah besar jenis di dalamnya, maka Anda dapat menggunakan LINQ paralel:
sumber
Referensi jawaban lain GetCustomAttributes . Menambahkan yang ini sebagai contoh menggunakan IsDefined
sumber
Seperti yang telah dinyatakan, refleksi adalah jalan yang harus ditempuh. Jika Anda akan sering menyebutnya, saya sangat menyarankan untuk menyimpan hasilnya, karena refleksi, terutama menghitung melalui setiap kelas, bisa sangat lambat.
Ini adalah potongan kode saya yang menjalankan semua jenis di semua rakitan yang dimuat:
sumber
Ini adalah peningkatan kinerja di atas solusi yang diterima. Iterasi meskipun semua kelas bisa lambat karena ada begitu banyak. Kadang-kadang Anda dapat menyaring seluruh unit tanpa melihat jenisnya.
Misalnya, jika Anda mencari atribut yang Anda nyatakan sendiri, Anda tidak mengharapkan DLL sistem mengandung tipe apa pun dengan atribut itu. Properti Assembly.GlobalAssemblyCache adalah cara cepat untuk memeriksa DLL sistem. Ketika saya mencoba ini pada program nyata saya menemukan saya bisa melewati 30.101 jenis dan saya hanya perlu memeriksa 1.983 jenis.
Cara lain untuk memfilter adalah dengan menggunakan Assembly.ReferencedAssemblies. Agaknya jika Anda ingin kelas dengan atribut tertentu, dan atribut itu didefinisikan dalam rakitan tertentu, maka Anda hanya peduli tentang rakitan itu dan rakitan lain yang merujuknya. Dalam pengujian saya ini membantu sedikit lebih banyak daripada memeriksa properti GlobalAssemblyCache.
Saya menggabungkan keduanya dan membuatnya lebih cepat. Kode di bawah ini mencakup kedua filter.
sumber
Dalam hal batasan .NET Portable , kode berikut harus berfungsi:
atau untuk sejumlah besar majelis yang menggunakan loop-state based
yield return
:sumber
Kami dapat memperbaiki jawaban Andrew dan mengonversi semuanya menjadi satu permintaan LINQ.
sumber