मैं गतिशील वस्तु के सदस्यों पर कैसे प्रतिबिंबित करूं?


131

मुझे .NET 4 में गतिशील कीवर्ड के साथ घोषित ऑब्जेक्ट से गुणों और उनके मूल्यों का शब्दकोश प्राप्त करने की आवश्यकता है? ऐसा लगता है कि इसके लिए प्रतिबिंब का उपयोग नहीं किया जाएगा।

उदाहरण:

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 = ???

जवाबों:


32

यदि ID DynamicsicMetaObjectProvider डायनामिक सदस्य नाम प्रदान कर सकता है, तो आप उन्हें प्राप्त कर सकते हैं। अपाचे लाइसेंस प्राप्त पीसीएल लाइब्रेरी डायनामाइटी (जिसे नगेट में पाया जा सकता है) में गेटमेयरनैम्स कार्यान्वयन देखें , यह एस और एस के लिए काम करता है जो लागू होता है और कोई अन्य जो बिना कस्टम परीक्षण के कार्यान्वयन के साथ मेटा ऑब्जेक्ट प्रदान करता है ।ExpandoObjectDynamicObjectGetDynamicMemberNamesIDynamicMetaObjectProviderGetDynamicMemberNamesis IDynamicMetaObjectProvider

सदस्य नाम प्राप्त करने के बाद मूल्य को सही तरीके से प्राप्त करने के लिए यह थोड़ा अधिक काम है, लेकिन इंप्रोमेप्टु ऐसा करता है लेकिन यह सिर्फ दिलचस्प बिट्स को इंगित करना कठिन है और यह समझ में आता है। यहां प्रलेखन है और यह प्रतिबिंब के बराबर या तेज है, हालांकि, एक्सपेंडो के लिए एक शब्दकोश लुकअप की तुलना में तेज़ होने की संभावना नहीं है, लेकिन यह किसी भी वस्तु, एक्सपेंडो, डायनेमिक या मूल के लिए काम करता है - आप इसे नाम देते हैं।


17
इस बिंदु पर आने के लिए धन्यवाद कोड है: var tTarget = लक्ष्य के रूप में IDynamicMetaObjectProvider; if (tTarget! = null) {tList.AddRange (tTarget.GetMetaObject (Expression.Constant (tTarget))। GetDynamicMemberNames ()); }
फ्लैटलाइनर DOA 12

आपके महान पुस्तकालय के लिए धन्यवाद। मैं मुद्दों इस पुस्तकालय के लिए एक गतिशील वस्तु राउंड ट्रिपिंग हो रही थी dynamicjson.codeplex.com , और कर रहा था अपने पुस्तकालय के साथ इसे बढ़ाया है।
JJS

1
उदाहरण कृपया।
14:17

105

ExpandoObject के मामले में, ExpandoObject वर्ग वास्तव में IDictionary<string, object>अपने गुणों के लिए लागू होता है , इसलिए समाधान कास्टिंग के रूप में तुच्छ है:

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

ध्यान दें कि यह सामान्य गतिशील वस्तुओं के लिए काम नहीं करेगा। इन मामलों में आपको ID DynamicsicMetaObjectProvider के माध्यम से DLR को छोड़ना होगा।


इसके लिए धन्यवाद, दुर्भाग्य से नमूना थोड़ा ओवरसिप्लांट किया गया था। मुझे एक गतिशील वस्तु का निरीक्षण करने में सक्षम होने की आवश्यकता है बिना यह जाने कि यह वास्तविक प्रकार क्या है।
फ्लैटलाइनर DOA

2
यह केवल एक्सपेंडीओबजेक्ट क्लास की वस्तुओं के लिए काम करता है, डायनेमिकऑब्जेक्ट क्लास एक अन्य एक्स्टेंसिबल क्लास है जो आईडीएएनएक्सएक्स को लागू नहीं करता है, बल्कि आईडी डायनामिक मैटाओबजेक्टपॉइडर को लागू करता है।
शरीक अब्दुल्ला

1
हालांकि यह ओपी के सवाल का जवाब देता है।
शरीक अब्दुल्ला

58

विचार करने के लिए कई परिदृश्य हैं। सबसे पहले, आपको अपनी वस्तु के प्रकार की जांच करने की आवश्यकता है। आप बस इसके लिए GetType () को कॉल कर सकते हैं। यदि प्रकार ID DynamicsicMetaObjectProvider को लागू नहीं करता है, तो आप किसी अन्य ऑब्जेक्ट के लिए प्रतिबिंब का उपयोग कर सकते हैं। कुछ इस तरह:

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

हालाँकि, ID DynamicsicMetaObjectProvider कार्यान्वयन के लिए, सरल प्रतिबिंब काम नहीं करता है। मूल रूप से, आपको इस ऑब्जेक्ट के बारे में अधिक जानने की आवश्यकता है। यदि यह ExpandoObject है (जो ID DynamicsicMetaObjectProvider कार्यान्वयन में से एक है), तो आप itowlson द्वारा दिए गए उत्तर का उपयोग कर सकते हैं। ExpandoObject अपने गुणों को एक शब्दकोश में संग्रहीत करता है और आप अपनी गतिशील वस्तु को एक शब्दकोश में डाल सकते हैं।

यदि यह डायनामिकऑब्जेक्ट (एक और ID डायनामिक मैटाओबजेक्टप्रूइडर इम्प्लीमेंटेशन) है, तो आपको इस डायनेमिकऑब्जेक्ट को उजागर करने के लिए जो भी तरीके इस्तेमाल करने की जरूरत है। डायनामिकऑब्जेक्ट को वास्तव में कहीं भी इसके गुणों की सूची को "स्टोर" करने की आवश्यकता नहीं है। उदाहरण के लिए, यह ऐसा कुछ कर सकता है (मैं अपने ब्लॉग पोस्ट से एक उदाहरण का पुन: उपयोग कर रहा हूं ):

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

इस स्थिति में, जब भी आप किसी संपत्ति (किसी भी नाम के साथ) का उपयोग करने का प्रयास करते हैं, तो वस्तु केवल संपत्ति के नाम को एक स्ट्रिंग के रूप में लौटाती है।

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

तो, आपके पास कुछ भी प्रतिबिंबित करने के लिए नहीं है - इस ऑब्जेक्ट में कोई गुण नहीं है, और एक ही समय में सभी वैध संपत्ति नाम काम करेंगे।

मैं ID DynamicsicMetaObjectProvider कार्यान्वयन के लिए कहूंगा, आपको ज्ञात कार्यान्वयन पर फ़िल्टर करने की आवश्यकता है, जहां आप संपत्तियों की एक सूची प्राप्त कर सकते हैं, जैसे कि ExpandoObject, और बाकी के लिए (या एक अपवाद फेंकें)।


7
यह सिर्फ मुझे लगता है कि यदि मैं जिस प्रकार का उपभोग करता हूं वह गतिशील है तो मुझे इसके अंतर्निहित प्रकार के बारे में धारणा नहीं बनानी चाहिए। मुझे सदस्यों की सूची प्राप्त करने के लिए GetDynamicMemberNames पर कॉल करने में सक्षम होना चाहिए। यह बेवकूफ लगता है कि स्थिर प्रकार में गतिशील लोगों की तुलना में बेहतर रनटाइम निरीक्षण समर्थन होता है!
फ्लैटलाइनर DOA

2
डायनेमिक ऑब्जेक्ट के लिए डायनामिक सदस्यों के सूची नामों को वापस करने के लिए आप GetDynamicMemberNames () विधि को ओवरराइड कर सकते हैं। समस्या यह है कि यह गारंटी नहीं है कि प्रत्येक गतिशील वस्तु में यह विधि है (ExpandoObject नहीं)। यह आश्चर्य की बात नहीं है कि प्रतिबिंब स्थिर प्रकारों के लिए बेहतर काम करता है। यह उनके लिए पहली जगह में बनाया गया था। गतिकी के साथ, आपको इकाई-परीक्षण और टीडीडी पर अधिक भरोसा करना होगा।
अलेक्जेंड्रा रुसिना

1
GetDynamicMemberNames () में एमएसडीएन डॉक्यूमेंटेशन का उल्लेख है: "यह विधि केवल डीबगिंग उद्देश्यों के लिए मौजूद है।", वास्तव में सुकून देने वाला नहीं :(
NicoJuicy

19

न्यूटनसॉफ्ट Json.Net की आवश्यकता है

थोड़ी देर हो गई, लेकिन मैं इसके साथ आया। यह आपको सिर्फ कुंजी देता है और फिर आप डायनामिक पर इसका उपयोग कर सकते हैं:

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;
}

तो आप बस इस तरह से foreach:

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

मान को एक स्ट्रिंग या किसी अन्य वस्तु के रूप में प्राप्त करने के लिए चुनना, या एक और गतिशील करना और फिर से लुकअप का उपयोग करना।


आप सूची सूची की जरूरत नहीं है।
aloisdg

4
उत्तम! मुझे जॉयजेक्ट एट्रिब्यूट्सजॉबजेक्ट = डायनामिकटॉइटप्रोपरेट्टीफोर बदलना पड़ा; ऑब्जेक्ट विशेषताएँ तक। JObject = (JObject) JToken.FromObject (obj); हालांकि!!
k25

बस @ k25 ने क्या दोहराया। आप को बदलने के लिए की जरूरत है JObject attributesAsJObject = dynamicToGetPropertiesFor;की तरह कुछ के साथ: var jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);। उस बिंदु पर, आप कुछ ऐसा करके संपत्ति के नाम और मूल्यों का शब्दकोश प्राप्त कर सकते हैं var objProperties = jObject.ToObject<Dictionary<string, object>>();। उस हाथ में, आप दौड़ के लिए रवाना हो रहे हैं। यह एक गतिशील की जरूरत नहीं है। यह ठीक उसी तरह से काम करता है जो सब-काDynamicObject
फ्लाईडॉग 57
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.