स्ट्रिंग के माध्यम से सी # गतिशील संपत्ति का मूल्य प्राप्त करें


182

मैं dynamicएक स्ट्रिंग के साथ एक सी # संपत्ति के मूल्य का उपयोग करना चाहता हूं :

dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };

यदि मुझे केवल स्ट्रिंग के रूप में "value2" है तो मैं d.value2 ("यादृच्छिक") का मूल्य कैसे प्राप्त कर सकता हूं? जावास्क्रिप्ट में, मैं मूल्य ("यादृच्छिक") तक पहुंचने के लिए d ["value2"] कर सकता था, लेकिन मुझे यकीन नहीं है कि यह c # और प्रतिबिंब के साथ कैसे किया जाए। निकटतम मैं यह आया हूँ:

d.GetType().GetProperty("value2") ... लेकिन मुझे नहीं पता कि इससे वास्तविक मूल्य कैसे मिलेगा।

हमेशा की तरह, आपकी मदद के लिए धन्यवाद!


26
ध्यान दें कि यह "गतिशील" का अभीष्ट उद्देश्य नहीं है और यह कि यह "गतिशील" के साथ किसी भी बेहतर काम नहीं करता है, जितना कि यह "वस्तु" के साथ है। "डायनामिक" जब पहुँच गुण करना संभव बनाता नाम संपत्ति का संकलन समय पर जाना जाता है, लेकिन प्रकार नहीं है। चूँकि आप जानते हैं कि संकलन समय पर न तो नाम और न ही प्रकार, गतिशील आपकी मदद करने वाला नहीं है।
एरिक लिपर्ट

संभवतः संबंधित: stackoverflow.com/questions/5877251/…
डकमास्ट्रो

3
@EricLippert मुझे पता है कि यह सवाल पुराना है, लेकिन अगर कोई इसे भविष्य में देखता है तो सिर्फ एक टिप्पणी करने के लिए। कुछ मामलों में आप यह नहीं चुन सकते हैं कि डायनेमिक या ऑब्जेक्ट का उपयोग करना है (उदाहरण के लिए JSON पार्सर का उपयोग करते हुए) और आप अभी भी एक स्ट्रिंग से संपत्तियों को प्राप्त करना चाह सकते हैं (उदाहरण के लिए एक कॉन्फ़िग फ़ाइल से) इसलिए यह उपयोग असामान्य नहीं है जैसा कि शुरू में कोई सोच सकता है।
पेड्रो

जवाबों:


217

एक बार जब आप अपने PropertyInfo(से GetProperty) होते हैं, तो आपको GetValueउस उदाहरण में कॉल करने और पास करने की आवश्यकता होती है जिससे आप मूल्य प्राप्त करना चाहते हैं। आपके मामले में:

d.GetType().GetProperty("value2").GetValue(d, null);

4
मैं 'd.GetType().GetProperty("value2").GetValue(d)' threw an exception of type 'System.Reflection.TargetInvocationException' dynamic {System.Reflection.TargetInvocationException}उस के साथ घड़ी की खिड़की में मिल रहा हूँ ..?
टिमडोग 23

6
थिंक GetValue को एक अतिरिक्त पैरामीटर की आवश्यकता होती है - egdGetType ()। GetProperty ("value2")। GetValue (d, null)
डोमर

3
क्या यह एक अनाम प्रकार के बजाय एक सच्चे गतिशील ExpandoObject पर काम करेगा? चूंकि new {}परिभाषित गुणों के साथ एक वास्तविक अनाम प्रकार का निर्माण होता है, GetType / GetProperty को कॉल करने से समझ में आता है, लेकिन एक्सपेंडेओबजेक्ट के बारे में क्या है, जिसे यदि आप GetType कहते हैं, तो आपको एक प्रकार मिलेगा जिसमें ExpandoObject के गुण हैं, लेकिन इसके गतिशील गुण हैं।
त्रिनको

16
-1। यह केवल साधारण .NET ऑब्जेक्ट्स के साथ काम करता है जो डायनामिक थे। यह किसी भी कस्टम डायनेमिक ऑब्जेक्ट जैसे कि Expando या ViewBag ASP ASP MVC का उपयोग नहीं करेगा
फिलिप

8
एक्सपेंडेओ ऑब्जेक्ट के साथ यह काम करता है: (((IDEDIA <string, object>) x)) ["value1"]
माइकल बाहिग

39
public static object GetProperty(object target, string name)
{
    var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
    return site.Target(site, target);
}

Microsoft.CSharp का संदर्भ जोड़ें। गतिशील प्रकार और निजी गुणों और क्षेत्रों के लिए भी काम करता है।

संपादित करें : जब यह दृष्टिकोण काम करता है, तो Microsoft से लगभग 20 × अधिक तेज़ विधि होती है। VisualBasic.dll असेंबली:

public static object GetProperty(object target, string name)
{
    return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}

2
बस यह उल्लेख करना चाहता था कि VisualBasic संस्करण आपके मूल 'GetProperty' संस्करण के बराबर नहीं है (GetProperty वास्तव में गतिशील GetMember को आमंत्रित करता है, जो IronPython में पायथन ऑब्जेक्ट्स पर भी काम करता है)।
ट्रेवर सुंदरबर्ग

वस्तु लक्ष्य क्या होगा?
Demodave

@Demodave वह वस्तु जिस पर आप संपत्ति ( dप्रश्न में) का आह्वान करना चाहते हैं ।
IllidanS4, मोनिका को

➕1 इसने निजी संपत्तियों के लिए काम किया जब FastMember और HyperDescriptor दोनों नहीं थे
क्रिस मैरिसिक

@ IllidanS4 जब आप CallSiteकोड बनाम CallByNameकोड की तुलना करते हैं तो क्या आपने CallSiteउदाहरण देते हुए दोनों की तुलना की थी ? मुझे संदेह होगा कि आपकी पहली विधि की लागत लगभग पूरी तरह से सक्रियण है Binderऔर CallSiteनहीं, का आह्वानTarget()
क्रिस मैरिकिक

24

डायनामाइट एक ओपन सोर्स .net stdलाइब्रेरी है, जिसे आप इसे dynamicकीवर्ड की तरह कहते हैं , लेकिन आपके लिए इसे कंपाइलर के बजाय प्रॉपर्टी के नाम के लिए एक स्ट्रिंग का उपयोग करते हैं, और यह प्रतिबिंब गति के बराबर होने पर समाप्त होता है (जो लगभग उतना तेज़ नहीं है डायनामिक कीवर्ड का उपयोग करने के रूप में, लेकिन यह गतिशील रूप से कैशिंग के अतिरिक्त ओवरहेड के कारण होता है, जहां संकलक सांख्यिकीय रूप से कैश करता है)।

Dynamic.InvokeGet(d,"value2");

11

एक संपत्ति के लिए setterऔर दोनों के लिए सबसे आसान तरीका getterजो किसी भी प्रकार के लिए काम करता है जिसमें शामिल है dynamicऔर ExpandoObjectइसका उपयोग करना है FastMemberजो कि सबसे तेज़ तरीका है (यह एमिट का उपयोग करता है)।

आप या तो TypeAccessorदिए गए प्रकार के आधार पर या किसी दिए गए प्रकार के ObjectAccessorउदाहरण के आधार पर प्राप्त कर सकते हैं ।

उदाहरण:

var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");

var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");

dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");

var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");

typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");

typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");

8

जब आप डायनेमिक ऑब्जेक्ट के लिए पूछते हैं, तो बहुत बार आपको एक एक्सपोऑबजेक्ट मिलता है (ऊपर दिए गए प्रश्न के अनाम-लेकिन-स्टेटिक रूप से टाइप किए गए उदाहरण में नहीं, लेकिन आप एक के लिए जावास्क्रिप्ट और मेरे चुने हुए JSON पार्सर JsonFx का उल्लेख करते हैं, एक विस्तारक उत्पन्न करता है)।

यदि आपका डायनामिक वास्तव में एक एक्सपेंडीओबजेक्ट है, तो आप इसे http://mdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx पर बताए अनुसार इसे IDEDIA को कास्ट करके प्रतिबिंब से बच सकते हैं ।

एक बार जब आप IDEDIA को कास्ट कर लेते हैं, तो आपके पास उपयोगी तरीकों जैसे .Item और .ContainsKey तक पहुंच होती है


दुर्भाग्य से, IDEDIA को कास्ट करने और उदाहरण के लिए TryGetValue का उपयोग करने के परिणामस्वरूप, एक पुरानी पुरानी वस्तु वापस आ रही है। आप उस बिंदु पर निहित ऑपरेटरों का लाभ नहीं उठा सकते हैं, क्योंकि उन्हें केवल संकलन समय पर माना जाता है। उदाहरण के लिए, यदि मेरे पास Int64 रूपांतरण के साथ Int64Proxy वर्ग था, तो Int64? i = data.value; //data is ExpandoObjectवह स्वतः ही लुकअप हो जाएगा और निहित ऑपरेटर को कॉल करेगा। दूसरी ओर, अगर मुझे यह मानने के लिए कि क्या "मान" फ़ील्ड मौजूद है, यह जांचने के लिए IDEDIA का उपयोग करना था, तो मुझे एक ऐसी वस्तु वापस मिल जाएगी जो Int64 के लिए त्रुटि के बिना डाली जाएगी। "
त्रिनको

5

GetProperty / GetValue Json डेटा के लिए काम नहीं करता है, यह हमेशा एक शून्य अपवाद उत्पन्न करता है, हालांकि, आप इस दृष्टिकोण की कोशिश कर सकते हैं:

JsonConvert का उपयोग करके अपनी वस्तु को क्रमबद्ध करें:

var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));

फिर इसे सीधे स्ट्रिंग पर वापस कास्टिंग पर एक्सेस करें:

var pn = (string)z["DynamicFieldName"];

यह Convert.ToString (अनुरोध) ["डायनामिकफिल्डनाम"] को लागू करने में सीधे काम कर सकता है, हालांकि मैंने परीक्षण नहीं किया है।


2
यह विधि त्रुटि उत्पन्न करती है: त्रुटि CS0021: टाइप 'ऑब्जेक्ट' की अभिव्यक्ति के लिए [] के साथ अनुक्रमण लागू नहीं किया जा सकता है। new JavaScriptSerializer().Deserialize<object>(json);आपके द्वारा सुझाए गए तरीके से "गुण" प्राप्त करने के लिए उपयोग करें
क्रिश किल्टन

4

d.GetType ()। getProperty ( "मान 2")

एक PropertyInfo ऑब्जेक्ट देता है।

तो फिर करो

propertyInfo.GetValue(d)

2
धन्यवाद, यह सही उत्तर था, लेकिन जैसा कि ऊपर उल्लेख किया गया है, GetValue(d)जरूरत हैGetValue(d,null)
टिमडॉग

4

यह वह तरीका है जो मुझे एक डायनामिक के संपत्ति मूल्य का मूल्य मिला है:

    public dynamic Post(dynamic value)
    {            
        try
        {
            if (value != null)
            {
                var valorCampos = "";

                foreach (Newtonsoft.Json.Linq.JProperty item in value)
                {
                    if (item.Name == "valorCampo")//property name
                        valorCampos = item.Value.ToString();
                }                                           

            }
        }
        catch (Exception ex)
        {

        }


    }

1

.GetType()रिटर्न करते समय गतिशील डॉक्टर से गुण प्राप्त करने के लिए null, यह प्रयास करें:

var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;

0

.Net कोर 3.1 में आप इस तरह की कोशिश कर सकते हैं

d?.value2 , d?.value3

0

स्वीकृत उत्तर के समान, आप GetFieldइसके बजाय भी प्रयास कर सकते हैं GetProperty

d.GetType().GetField("value2").GetValue(d);

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


C # 3.0+ में संपत्ति और फील्ड के बीच FYI का अंतर: stackoverflow.com/a/653799/2680660
Efreeto
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.