Bagaimana cara saya merefleksikan anggota objek dinamis?


131

Saya perlu mendapatkan kamus properti dan nilainya dari objek yang dideklarasikan dengan kata kunci dinamis di .NET 4? Tampaknya menggunakan refleksi untuk ini tidak akan berhasil.

Contoh:

dynamic s = new ExpandoObject();
s.Path = "/Home";
s.Name = "Home";

// How do I enumerate the Path and Name properties and get their values?
IDictionary<string, object> propertyValues = ???

Jawaban:


32

Jika IDynamicMetaObjectProvider dapat memberikan nama anggota dinamis, Anda bisa mendapatkannya. Lihat implementasi GetMemberNames di pustaka PCL berlisensi Dynamitey (yang dapat ditemukan di nuget), ia berfungsi untuk ExpandoObjects dan DynamicObjects yang mengimplementasikan GetDynamicMemberNamesdan siapa pun IDynamicMetaObjectProvideryang menyediakan objek meta dengan implementasi GetDynamicMemberNamestanpa pengujian khusus di luaris IDynamicMetaObjectProvider .

Setelah mendapatkan nama-nama anggota, itu sedikit lebih banyak pekerjaan untuk mendapatkan nilai dengan cara yang benar, tetapi Impromptu melakukan ini tetapi lebih sulit untuk menunjuk ke bit yang menarik dan membuatnya masuk akal. Berikut dokumentasi dan sama atau lebih cepat dari refleksi, namun, tidak mungkin lebih cepat daripada pencarian kamus untuk ekspansi, tetapi berfungsi untuk objek apa pun, ekspansi, dinamis atau asli - sebut saja.


17
Terima kasih untuk sampai ke titik kode adalah: var tTarget = target as IDynamicMetaObjectProvider; if (tTarget! = null) {tList.AddRange (tTarget.GetMetaObject (Expression.Constant (tTarget)). GetDynamicMemberNames ()); }
Flatliner DOA

terima kasih atas perpustakaan Anda yang hebat. Saya mengalami masalah memutar- balikkan objek dinamis ke perpustakaan ini dynamicjson.codeplex.com , dan dapat memperpanjangnya dengan perpustakaan Anda.
JJS

1
contoh tolong.
Demodave

105

Dalam kasus ExpandoObject, kelas ExpandoObject sebenarnya mengimplementasikan IDictionary<string, object>untuk propertinya, sehingga solusinya sepele seperti casting:

IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;

Perhatikan bahwa ini tidak akan berfungsi untuk objek dinamis umum. Dalam kasus ini, Anda harus drop down ke DLR melalui IDynamicMetaObjectProvider.


Terima kasih untuk itu, sayangnya sampelnya terlalu disederhanakan. Saya harus dapat memeriksa objek yang dinamis tanpa mengetahui apa itu tipe nyata.
Flatliner DOA

2
Ini hanya berfungsi untuk objek dari kelas ExpandoObject, kelas DynamicObject adalah kelas extensible lain yang tidak mengimplementasikan IDictionary tetapi mengimplementasikan IDynamicMetaObjectProvider.
Sharique Abdullah

1
Itu memang menjawab pertanyaan OP sekalipun.
Sharique Abdullah

58

Ada beberapa skenario untuk dipertimbangkan. Pertama-tama, Anda perlu memeriksa jenis objek Anda. Anda cukup memanggil GetType () untuk ini. Jika jenisnya tidak mengimplementasikan IDynamicMetaObjectProvider, maka Anda dapat menggunakan refleksi yang sama dengan objek lainnya. Sesuatu seperti:

var propertyInfo = test.GetType().GetProperties();

Namun, untuk implementasi IDynamicMetaObjectProvider, refleksi sederhana tidak berfungsi. Pada dasarnya, Anda perlu tahu lebih banyak tentang objek ini. Jika itu adalah ExpandoObject (yang merupakan salah satu implementasi IDynamicMetaObjectProvider), Anda dapat menggunakan jawaban yang disediakan oleh itowlson. ExpandoObject menyimpan propertinya dalam kamus dan Anda bisa dengan mudah memasukkan objek dinamis Anda ke kamus.

Jika DynamicObject (implementasi IDynamicMetaObjectProvider lain), maka Anda perlu menggunakan metode apa pun yang dipaparkan DynamicObject ini. DynamicObject tidak diharuskan untuk benar-benar "menyimpan" daftar propertinya di mana saja. Misalnya, mungkin melakukan sesuatu seperti ini (saya menggunakan kembali contoh dari posting blog saya ):

public class SampleObject : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = binder.Name;
        return true;
    }
}

Dalam kasus ini, setiap kali Anda mencoba mengakses properti (dengan nama yang diberikan), objek hanya mengembalikan nama properti sebagai string.

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".

Jadi, Anda tidak memiliki apa pun untuk dipantulkan - objek ini tidak memiliki properti apa pun, dan pada saat yang sama semua nama properti yang valid akan berfungsi.

Saya akan mengatakan untuk implementasi IDynamicMetaObjectProvider, Anda perlu memfilter implementasi yang dikenal di mana Anda bisa mendapatkan daftar properti, seperti ExpandoObject, dan abaikan (atau lempar pengecualian) untuk sisanya.


7
Sepertinya bagi saya bahwa jika jenis yang saya konsumsi adalah Dinamis maka saya tidak boleh membuat asumsi tentang jenis yang mendasarinya. Saya harus dapat memanggil GetDynamicMemberNames untuk mendapatkan daftar anggota. Tampaknya bodoh bahwa tipe statis memiliki dukungan inspeksi runtime yang lebih baik daripada yang dinamis!
Flatliner DOA

2
Anda bisa mengganti metode GetDynamicMemberNames () untuk objek dinamis untuk mengembalikan nama daftar anggota dinamis. Masalahnya adalah itu tidak dijamin bahwa setiap objek dinamis memiliki metode ini (ExpandoObject tidak). Tidak mengherankan bahwa refleksi bekerja lebih baik untuk tipe statis. Itu diciptakan untuk mereka di tempat pertama. Dengan dinamika, Anda harus lebih mengandalkan pengujian unit dan TDD.
Alexandra Rusina

1
Dokumentasi MSDN untuk GetDynamicMemberNames () menyebutkan: "Metode ini hanya ada untuk keperluan debugging.", Tidak benar-benar menghibur :(
NicoJuicy

19

Membutuhkan Newtonsoft Json.Net

Sedikit terlambat, tetapi saya datang dengan ini. Ini memberi Anda hanya kunci dan kemudian Anda dapat menggunakannya pada dinamis:

public List<string> GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor)
{
    JObject attributesAsJObject = dynamicToGetPropertiesFor;
    Dictionary<string, object> values = attributesAsJObject.ToObject<Dictionary<string, object>>();
    List<string> toReturn = new List<string>();
    foreach (string key in values.Keys)
    {
        toReturn.Add(key);                
    }
    return toReturn;
}

Maka Anda cukup foreach seperti ini:

foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
    dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
    // And
    dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}

Memilih untuk mendapatkan nilai sebagai string atau objek lain, atau lakukan dinamika lain dan gunakan pencarian lagi.


Anda tidak perlu daftar untuk Kembali.
aloisdg pindah ke codidact.com

4
Sempurna! Saya harus mengubah atribut JObjectAsJObject = dynamicToGetPropertiesFor; to Object attributesAsJObject = (JObject) JToken.FromObject (obj); meskipun!!
k25

Hanya untuk mengulangi apa yang dikatakan @ k25. Anda perlu mengganti JObject attributesAsJObject = dynamicToGetPropertiesFor;dengan sesuatu seperti: var jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);. Pada titik itu, Anda bisa mendapatkan kamus nama dan nilai properti dengan melakukan sesuatu seperti var objProperties = jObject.ToObject<Dictionary<string, object>>();. Dengan itu di tangan, Anda pergi ke balapan. Ini tidak perlu dinamis. Ini berfungsi baik dengan apa pun yang merupakan subkelas dariDynamicObject
Flydog57
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.