2010-10-14 12 views
22

पर गतिशील ऑब्जेक्ट में सदस्यों को जोड़ना मैं .NET 4.0 में डायनामिक ऑब्जेक्ट मॉडल की खोज कर रहा हूं। एप्लिकेशन वह है जहां किसी ऑब्जेक्ट को किसी प्रकार की टेक्स्ट/एक्सएमएल फ़ाइल के माध्यम से वर्णित किया जाएगा, और प्रोग्राम को उस फ़ाइल को पढ़ने पर एक ऑब्जेक्ट बनाना होगा।रनटाइम

डायनामिक ऑब्जेक्ट के साथ, हम सदस्यों को आसानी से जोड़ सकते हैं, बशर्ते कि हम सदस्य का नाम प्राथमिकता दें। लेकिन, अगर हम सदस्य के नाम को जोड़ने के लिए भी नहीं जानते हैं तो क्या होगा? क्या गतिशील बनाने का कोई तरीका है?

उदाहरण के लिए, मैं सदस्यों के Property1 'के साथ एक वस्तु बनाने की जरूरत कहते हैं,' Property2 ', और' PropertyA 'के साथ एक और वस्तु है, और के रूप में पाठ/एक्सएमएल फ़ाइल द्वारा वर्णित' PropertyB '। मैं इस जानकारी के आधार पर गतिशील रूप से एक वस्तु कैसे बना सकता हूं?

अद्यतन मैं इस पोस्ट से कुछ विचार है:

dynamic d = new PFDynamicChannel(); 
PFCouplings c = ((PFChannel)d).Coupling; 
d.NewProperty = "X"; 

कारण मैं उपयोग करने के लिए एक शब्दकोश है इच्छा नहीं है: http://www.codeproject.com/KB/cs/dynamicincsharp.aspx

इस कार्यान्वयन मेरा पीछा कर की तरह कुछ करने की अनुमति देता TryGetMember का उपयोग करने के लिए, और TrySetMember विधियों को मैं ओवरराइड कर सकता हूं, जिसके अंतर्गत मैं प्रोग्राम के लिए जरूरी घटनाओं को बढ़ा सकता हूं।

इस तरह, मैं बेस क्लास (पीएफसीएचनल) से प्राप्त कर सकता हूं, लेकिन मैं फ्लाई पर सदस्यों को भी जोड़ सकता हूं। लेकिन, मेरी समस्या यह है कि मैं रनटाइम तक नई संपत्ति का नाम नहीं जानूंगा। और, मुझे वास्तव में नहीं लगता कि गतिशील वस्तु मुझे फ्लाई पर नई गुण जोड़ने की अनुमति देती है। यदि ऐसा है, तो मैं इस क्षमता को देने के लिए ExpandoObject का उपयोग कैसे कर सकता हूं?

+2

आप अभी भी समझ में नहीं आता क्यों गतिशील और ExpandoObject .NET में मिला। कारण आप जो चाहते हैं उसके सटीक oposite था। ExpandoObject अभी भी शब्दकोश का उपयोग करता है , अच्छी तरह से यह शब्दकोश है। कंपाइलर केवल "संपत्ति" कॉल को शब्दकोश [NameOfProperty] में अनुवाद करता है। यह कोड बहुत अच्छा बनाता है। लेकिन यह सब कुछ है, इसकी एकमात्र कोड-चीनी है। जो भी आप चाहते हैं उसे किसी गतिशील टाइपिंग के साथ भी शब्दकोश के साथ प्राप्त किया जा सकता है। – Euphoric

+0

शब्दकोश वस्तुओं के रूप में उठाए जाने वाले कार्यक्रमों के बारे में क्या सेट किया गया है? – sbenderli

+0

संभावित डुप्लिकेट [गतिशील रूप से गतिशील वस्तु में सदस्यों को जोड़ना] (http: // stackoverflow।कॉम/प्रश्न/2079870/गतिशील रूप से जोड़ने-सदस्यों-टू-ए-डायनामिक-ऑब्जेक्ट) – nawfal

उत्तर

37

यदि आप केवल ऐसा करने की आवश्यकता है, तो आपको ExpandoObject पर देखना चाहिए। यदि आपको और अभी भी DynamicObject का उपयोग करने की आवश्यकता है, तो आपको संपत्ति मूल्यों को याद रखने के लिए कोड लिखना होगा, मूल रूप से ... जो आप संभावित रूप से एम्बेडेड ExpandoObject के साथ कर सकते हैं।

यह मुझे स्पष्ट नहीं है कि आप इस ऑब्जेक्ट के साथ क्या करना चाहते हैं, हालांकि - क्या आपको यकीन है कि आपको गतिशील टाइपिंग की आवश्यकता है? क्या Dictionary<string, object> वास्तव में कोई और बुरा होगा? यह मूल रूप से बाद में ऑब्जेक्ट का उपभोग करने जा रहा है पर निर्भर करता है।

+0

ठीक है, ऑब्जेक्ट को वास्तव में बेसक्लास का उत्तराधिकारी होना आवश्यक है। बेसक्लास कई कार्यक्रमों और गुणों को परिभाषित करता है जो शेष कार्यक्रम के लिए आवश्यक हैं। डायनामिक ऑब्जेक्ट में मुझे रूचि रखने का एक कारण यह है कि मैं TryGetMember और TrySetMember विधियों को ओवरराइड कर सकता हूं, जिसके अंतर्गत मुझे ईवेंट जुटाने की आवश्यकता है। लेकिन, कोड का एक टुकड़ा कैसे एक सदस्य को जोड़ता है जिसका नाम प्राथमिकता जैसा नहीं है? – sbenderli

+0

@sbenderli - फिर आप अपने बेसक्लास से प्राप्त नई ऑब्जेक्ट बना सकते हैं और यह ऑब्जेक्ट "अज्ञात" गुणों के बारे में जानकारी रखने के लिए शब्दकोश का उपयोग कर सकता है। – Euphoric

+0

कृपया मेरा अपडेट – sbenderli

6

मुझे यकीन नहीं है कि आप इस मामले में एक गतिशील वस्तु का उपयोग करना चाहते हैं।

सी # में गतिशील आप अपना काम करने दिया तरह बातें:

dynamic something = GetUnknownObject(); 
    something.aPropertyThatShouldBeThere = true; 

आप एक ExpandoObject का उपयोग करते हैं, तो आप कर सकते हैं:

var exp = GetMyExpandoObject(); 
    exp.APropertyThatDidntExist = "something"; 

इन दोनों आप प्रॉपर्टी का उपयोग के रूप में अगर यह वास्तव में मौजूद जाने संकलन समय पर। आपके मामले में, आपको इस वाक्यविन्यास का बिल्कुल उपयोग करने की आवश्यकता नहीं होगी, इसलिए मुझे यकीन नहीं है कि इससे आपको कोई लाभ मिलेगा। इसके बजाय, क्यों सिर्फ एक Dictionary<string, object>, और उपयोग नहीं:

var props = new Dictionary<string, object>(); 
    foreach(var someDefinintion in aFile) 
    { 
     props[ someDefinition.Name] = someDefinition.value; 
    } 

एक Dictionary<string,object> क्योंकि क्या एक expando वस्तु है मूल रूप से है - लेकिन यह एक अलग वाक्य रचना के लिए समर्थन हासिल है। हां, मैं सरलीकृत कर रहा हूं - लेकिन यदि आप इसे अन्य कोड से या बाध्यकारी/आदि के माध्यम से उपयोग नहीं कर रहे हैं, तो यह मूल रूप से सच है।

+0

कृपया मेरा अपडेट देखें – sbenderli

0

dynamic प्रकार मूल रूप से संपत्ति बैग के रूप में कार्यान्वित किया जाता है। इसका मतलब कुंजी (संपत्ति नाम) और वस्तुओं (यहां गैर-प्रकार-सुरक्षित तरीके से) का शब्दकोश है। यदि आप इस शब्दकोश में सीधे प्रवेश कर सकते हैं, तो आप इसका उपयोग नहीं करते हैं, लेकिन आप अपने आप से शब्दकोश का उपयोग कर सकते हैं।

अरे, जॉन स्कीट तेजी :(

25

इस के अनुसार किया गया था: Adding properties and methods to an ExpandoObject, dynamically!,

... आप अपने मूल्य धारक के रूप में एक expando वस्तु का उपयोग कर सकते हैं, और एक IDictionary < स्ट्रिंग, वस्तु के लिए यह डाली > जब आप गतिशील रूप से नामित गुण जोड़ना चाहते हैं।

उदाहरण

dynamic myobject = new ExpandoObject(); 

IDictionary<string, object> myUnderlyingObject = myobject; 

myUnderlyingObject.Add("IsDynamic", true); // Adding dynamically named property 

Console.WriteLine(myobject.IsDynamic); // Accessing the property the usual way 

गु परीक्षण किया जाता है और कंसोल स्क्रीन पर "सत्य" प्रिंट करेगा।

बेशक, आपके मामले में, जहां आपके मौलिक वस्तु किसी अन्य वर्ग से प्राप्त करना है में, इस उदाहरण सिर्फ एक संभावित कस्टम कार्यान्वयन के लिए आप जानकारी देने के लिए दिया जाता है।

हो सकता है कि अपने वर्ग कार्यान्वयन में एक expando वस्तु सहित और कॉल पुनः निर्देशित tryget और अपनी कक्षा में expando वस्तु के उदाहरण के लिए tryset के लिए?

अद्यतन

अगर आपके आधार वर्ग DynamicObject से निकला है (अर्थात आपका ओवरराइड कर सकते हैं सभी TrySet/प्राप्त/तरीकों आह्वान) तो, आप भी एक शब्दकोश आंतरिक रूप से इस्तेमाल कर सकते हैं। कोशिश/सेट ओवरराइड करने के प्रयास में आप किसी भी घटना फायरिंग को चाहते हैं, और आंतरिक शब्दकोश में सेटिंग को प्रतिनिधि दें।

एक नई संपत्ति जोड़ने के लिए (या मौजूदा एक को हटाएं) आप TryInvoke को ओवरराइड कर सकते हैं। जब मॉथोड नाम होता है, उदाहरण के लिए, "एडप्रोपर्टी" और टाइप स्ट्रिंग का एक तर्क होता है तो आप तर्क के नाम से अपने शब्दकोश में एक नया आइटम जोड़ देंगे। इसी तरह आप गतिशील रूप से "RemoveProperty" को परिभाषित करेंगे। आपको एक विस्तार ऑब्जेक्ट की भी आवश्यकता नहीं है।

class MyBaseClass: DynamicObject 
{ 
    // usefull functionality 
} 

class MyClass: MyBaseClass 
{ 
    Dictionary<string, object> dynamicProperties = new Dictionary<string, object>(); 

    override bool TryGetMember(...) 
    { 
     // read the value of the requested property from the dictionary 
     // fire any events and return 
    } 

    override bool TrySetMember(...) 
    { 
     // set the value of the requested property to the dictionary 
     // if the property does not exist, 
     // add it to the dictionary (compile time dynamic property naming) 
     // fire any events 
    } 

    override bool TryInvoke(...) 
    { 
     // check what method is requested to be invoked 
     // is it "AddProperty"?? 
     // if yes, check if the first argument is a string 
     // if yes, add a new property to the dictionary 
     // with the name given in the first argument (runtime dynamic property naming) 
     // if there is also a second argument of type object, 
     // set the new property's value to that object. 

     // if the method to be invoked is "RemoveProperty" 
     // and the first argument is a string, 
     // remove from the Dictionary the property 
     // with the name given in the first argument. 

     // fire any events 
    } 
} 

// USAGE 
static class Program 
{ 
    public static void Main() 
    { 
     dynamic myObject = new MyClass(); 

     myObject.FirstName = "John"; // compile time naming - TrySetMember 
     Console.WriteLine(myObject.FirstName); // TryGetMember 

     myObject.AddProperty("Salary"); // runtime naming (try invoke "AddProperty" with argument "Salary") 
     myObject.Salary = 35000m; 
     Console.WriteLine(myObject.Salary); // TryGetMember 

     myObject.AddProperty("DateOfBirth", new DateTime(1980,23,11)); // runtime naming (try invoke "AddProperty" with fisrt argument "DateOfBirth" and second argument the desired value) 
     Console.WriteLine(myObject.DateOfBirth); // TryGetMember 

     myObject.RemoveProperty("FirstName"); // runtime naming (try invoke "RemoveProperty" with argument "FirstName") 

     Console.WriteLine(myObject.FirstName); // Should print out empty string (or throw, depending on the desired bahavior) because the "FirstName" property has been removed from the internal dictionary. 

    } 
} 

बेशक, जैसा कि मैंने कहा था, यह केवल तभी काम करेगा जब आपकी बेस क्लास डायनामिक ऑब्जेक्ट से निकलती है।

1

Thanasis Ioannidis जवाब देने के लिए संबंधित एक संस्करण "अपने आधार वर्ग DynamicObject से निकला है, तो", वहाँ एक आसान तरीका है, सिर्फ इस तरह "MyClass" वर्ग में विधि AddProperty जोड़ने के बारे में:

class MyClass: MyBaseClass 
    { 
     Dictionary<string, object> dynamicProperties = new Dictionary<string, object>(); 

     public void AddProperty(string key, object value){ 
      dynamicProperties[key] = value; 
     } 

तो फिर तुम

dynamic myObject = new MyClass(); 
myObject.AddProperty("DateOfBirth", new DateTime(1980,23,11)); 

आपको "TryInvoke" पर किसी भी ओवरराइड की आवश्यकता नहीं है।