Situasi saya sangat sederhana. Di suatu tempat dalam kode saya, saya punya ini:
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
//How to do this?
if (myVariable.MyProperty.Exists)
//Do stuff
Jadi, pada dasarnya pertanyaan saya adalah bagaimana memeriksa (tanpa mengeluarkan pengecualian) bahwa properti tertentu tersedia pada variabel dinamis saya. Saya bisa melakukannya GetType()
tetapi saya lebih suka menghindari itu karena saya tidak benar-benar perlu tahu jenis objeknya. Yang saya benar-benar ingin tahu adalah apakah sebuah properti (atau metode, jika itu membuat hidup lebih mudah) tersedia. Ada petunjuk?
c#
dynamic
dynamic-keyword
krisis bundar
sumber
sumber
Jawaban:
Saya pikir tidak ada cara untuk mengetahui apakah suatu
dynamic
variabel memiliki anggota tertentu tanpa mencoba mengaksesnya, kecuali jika Anda menerapkan kembali cara pengikatan dinamis ditangani dalam kompiler C #. Yang mungkin akan mencakup banyak tebakan, karena itu adalah implementasi yang ditentukan, sesuai dengan spesifikasi C #.Jadi, Anda harus benar-benar mencoba mengakses anggota dan menangkap pengecualian, jika gagal:
sumber
IDictionary
dan bekerja dengan itu, itu hanya berfungsiExpandoObject
, itu tidak akan bekerja padadynamic
objek lain .RuntimeBinderException
ada diMicrosoft.CSharp.RuntimeBinder
namespace.Saya pikir saya akan melakukan perbandingan jawaban Martijn dan jawaban svick ...
Program berikut mengembalikan hasil berikut:
Sebagai hasilnya saya sarankan menggunakan refleksi.Lihat di bawah.Menanggapi komentar bland:
Rasio adalah
reflection:exception
kutu untuk 100000 iterasi:... cukup adil - jika Anda mengharapkannya gagal dengan probabilitas kurang dari ~ 1/47, maka pilih pengecualian.
Di atas mengasumsikan bahwa Anda menjalankan
GetProperties()
setiap waktu. Anda mungkin dapat mempercepat proses dengan menyimpan hasilGetProperties()
untuk setiap jenis dalam kamus atau sejenisnya. Ini dapat membantu jika Anda memeriksa serangkaian tipe yang sama berulang kali.sumber
IIDynamicMetaObjectProvider
. Saya mengerti motivasi di balik jawaban Anda, dan menghargainya. Cukup adil untuk menjawabnya.Mungkin menggunakan refleksi?
sumber
Where
:.Any(p => p.Name.Equals("PropertyName"))
((Type)myVar.GetType()).GetProperties().Any(x => x.Name.Equals("PropertyName"))
. Pemain untuk mengetik diperlukan untuk membuat kompiler senang tentang lambda.Untuk berjaga-jaga jika itu membantu seseorang:
Jika metode
GetDataThatLooksVerySimilarButNotTheSame()
mengembalikan suatuExpandoObject
Anda juga dapat melemparkan keIDictionary
sebelum memeriksa.sumber
Dua solusi umum untuk ini termasuk membuat panggilan dan menangkap
RuntimeBinderException
, menggunakan refleksi untuk memeriksa panggilan, atau membuat serial ke format teks dan parsing dari sana. Masalah dengan pengecualian adalah mereka sangat lambat, karena ketika seseorang dibangun, tumpukan panggilan saat ini adalah serial. Serialising ke JSON atau sesuatu yang analog menghasilkan penalti yang sama. Ini meninggalkan kita dengan refleksi tetapi hanya berfungsi jika objek yang mendasarinya sebenarnya adalah POCO dengan anggota nyata di atasnya. Jika itu pembungkus dinamis di sekitar kamus, objek COM, atau layanan web eksternal, maka refleksi tidak akan membantu.Solusi lain adalah menggunakan
DynamicMetaObject
untuk mendapatkan nama anggota sebagaimana DLR melihatnya. Dalam contoh di bawah ini, saya menggunakan kelas statis (Dynamic
) untuk mengujiAge
bidang dan menampilkannya.sumber
Dynamitey
paket nuget sudah melakukan ini. ( nuget.org/packages/Dynamitey )Jawaban Denis membuat saya berpikir untuk solusi lain menggunakan JsonObjects,
pemeriksa properti header:
atau mungkin lebih baik:
sebagai contoh:
sumber
Yah, saya menghadapi masalah yang sama tetapi pada unit test.
Menggunakan SharpTestsEx Anda dapat memeriksa apakah suatu properti ada. Saya menggunakan ini menguji pengontrol saya, karena karena objek JSON dinamis, seseorang dapat mengubah nama dan lupa untuk mengubahnya di javascript atau sesuatu, jadi pengujian untuk semua properti saat menulis controller harus meningkatkan keselamatan saya.
Contoh:
Sekarang, menggunakan SharTestsEx:
Dengan menggunakan ini, saya menguji semua properti yang ada menggunakan "Should (). NotThrow ()".
Mungkin di luar topik, tetapi dapat bermanfaat bagi seseorang.
sumber
((string)(testedObject.MyName)).Should().Be("I am a testing object");
Mengikuti dari jawaban oleh @karask, Anda dapat membungkus fungsi sebagai penolong seperti:
sumber
Bagi saya ini bekerja:
sumber
null
tidak berarti properti tidak adaJika Anda mengontrol tipe yang digunakan sebagai dinamis, tidak bisakah Anda mengembalikan tuple alih-alih nilai untuk setiap akses properti? Sesuatu seperti...
Mungkin merupakan implementasi yang naif, tetapi jika Anda membangun salah satu dari ini secara internal setiap kali dan mengembalikannya sebagai ganti nilai aktual, Anda dapat memeriksa
Exists
setiap akses properti dan kemudian menekannyaValue
jika itu benar dengan nilainyadefault(T)
(dan tidak relevan) jika tidak.Yang mengatakan, saya mungkin kehilangan beberapa pengetahuan tentang bagaimana dinamis bekerja dan ini mungkin bukan saran yang bisa diterapkan.
sumber
Dalam kasus saya, saya perlu memeriksa keberadaan metode dengan nama tertentu, jadi saya menggunakan antarmuka untuk itu
Selain itu, antarmuka dapat berisi lebih dari sekadar metode:
Dari: Antarmuka (Panduan Pemrograman C #)
Elegan dan tidak perlu menjebak pengecualian atau bermain dengan refleksi ...
sumber
Saya tahu ini benar-benar posting lama tapi di sini ada solusi sederhana untuk bekerja dengan
dynamic
mengetikc#
.sumber
Sebagai
ExpandoObject
warisan,IDictionary<string, object>
Anda dapat menggunakan pemeriksaan berikutAnda dapat membuat metode utilitas untuk melakukan pemeriksaan ini, yang akan membuat kode lebih bersih dan dapat digunakan kembali
sumber
Ini cara lain:
sumber
dynamic
.dynamic
kata kunci adalah subjek yang jauh lebih luas. Go cek jika Anda dapat mengujiCount
didynamic foo = new List<int>{ 1,2,3,4 }
seperti itu