शब्दकोश और इसके विपरीत के लिए मानचित्रण वस्तु


90

क्या किसी शब्दकोश और इसके विपरीत में ऑब्जेक्ट मैप करने का कोई सुंदर त्वरित तरीका है?

उदाहरण:

IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....

हो जाता है

SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........

सबसे तेज़ तरीका प्रोटोबुफ़ की तरह कोड-पीढ़ी द्वारा होगा ... मैंने अभिव्यक्ति के पेड़ों का उपयोग प्रतिबिंब से बचने के लिए जितनी बार संभव हो किया है
कोनराड

नीचे दिए गए सभी स्व-कोडित उत्तर गहरे रूपांतरण का समर्थन नहीं करते हैं और वास्तविक जीवन के अनुप्रयोगों में काम नहीं करेंगे। के रूप में earnerplates ने सुझाव दिया आप Newtonsoft जैसे कुछ पुस्तकालय का उपयोग करना चाहिए
सीजर

जवाबों:


175

दो विस्तार विधियों में कुछ प्रतिबिंब और जेनरिक का उपयोग करके आप इसे प्राप्त कर सकते हैं।

सही, दूसरों ने ज्यादातर एक ही समाधान किया, लेकिन यह कम प्रतिबिंब का उपयोग करता है जो अधिक प्रदर्शन-वार है और अधिक पठनीय है:

public static class ObjectExtensions
{
    public static T ToObject<T>(this IDictionary<string, object> source)
        where T : class, new()
    {
            var someObject = new T();
            var someObjectType = someObject.GetType();

            foreach (var item in source)
            {
                someObjectType
                         .GetProperty(item.Key)
                         .SetValue(someObject, item.Value, null);
            }

            return someObject;
    }

    public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
    {
        return source.GetType().GetProperties(bindingAttr).ToDictionary
        (
            propInfo => propInfo.Name,
            propInfo => propInfo.GetValue(source, null)
        );

    }
}

class A
{
    public string Prop1
    {
        get;
        set;
    }

    public int Prop2
    {
        get;
        set;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, object> dictionary = new Dictionary<string, object>();
        dictionary.Add("Prop1", "hello world!");
        dictionary.Add("Prop2", 3893);
        A someObject = dictionary.ToObject<A>();

        IDictionary<string, object> objectBackToDictionary = someObject.AsDictionary();
    }
}

मुझे कार्यान्वयन पसंद है, मैंने वास्तव में इसका उपयोग करना शुरू कर दिया था, लेकिन क्या आपके पास प्रदर्शन पर कोई प्रतिक्रिया है? मुझे पता है कि प्रदर्शन की बात आती है तो प्रतिबिंब सबसे बड़ा नहीं है? क्या आपकी कोई टिप्पणी है?
18

@nolimit वास्तव में मुझे इसके वास्तविक प्रदर्शन का पता नहीं है, लेकिन मुझे लगता है कि यह बुरा नहीं है (परावर्तन से बचने से भी बुरा, निश्चित रूप से ...)। वास्तव में, विकल्प क्या है? परियोजनाओं की आवश्यकताओं के आधार पर, शायद अन्य विकल्प हैं, जैसे गतिशील टाइपिंग का उपयोग करना जो प्रतिबिंब से कहीं अधिक तेज है ... कौन जानता है! :)
मैटिस फिडेमाइजर

अच्छी तरह से मेरे मामले में विकल्प असाइनमेंट द्वारा ऑब्जेक्ट के निर्माण के रूप में सरल है, लेकिन मैं ऑब्जेक्ट बनाने के लिए एक नीरस अभी तक सस्ती तरीके की तलाश कर रहा हूं। कहा कि, मैं ने पाया है यह जो मेरे लिए मतलब है कि यह बहुत महंगा कोड के उस टुकड़े का उपयोग नहीं है।
नवमीत

@nolimit हाँ, ऐसा लगता है कि कोई समस्या नहीं है। यह आवश्यक समस्या के लिए सही उपकरण का उपयोग करने के बारे में है: डी आपके मामले में, यह एक आकर्षण की तरह काम करना चाहिए। मुझे विश्वास है कि मैं अभी तक कोड में कुछ धुन सकता हूं!
मैटिस फिडेमाइजर

@nolimit जाँच करें कि अब प्रत्येक संपत्ति के लिए पहले विधि में अब और GetType()नहीं बुलाया गया है someObject
मैटिस फिडेमाइजर

30

न्यूटनसॉफ्ट के साथ सबसे पहले डिक्शनरी को JSON स्ट्रिंग में बदलें।

var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);

फिर JSON स्ट्रिंग को अपनी ऑब्जेक्ट के लिए डिसेरलाइज़ करें

var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);

1
सरल और रचनात्मक!
कमलप्रीत

1
सावधानी के साथ इस दृष्टिकोण का उपयोग करें। यदि यह कई (सैकड़ों) शब्दकोशों के लिए उपयोग किया जाता है, तो यह आपके एप्लिकेशन को बंद कर देगा।
amackay11

12

लगता है कि प्रतिबिंब केवल यहाँ मदद करता है .. मैंने ऑब्जेक्ट को डिक्शनरी और वाइस वर्सा में बदलने का छोटा सा उदाहरण दिया है:

[TestMethod]
public void DictionaryTest()
{
    var item = new SomeCLass { Id = "1", Name = "name1" };
    IDictionary<string, object> dict = ObjectToDictionary<SomeCLass>(item);
    var obj = ObjectFromDictionary<SomeCLass>(dict);
}

private T ObjectFromDictionary<T>(IDictionary<string, object> dict)
    where T : class 
{
    Type type = typeof(T);
    T result = (T)Activator.CreateInstance(type);
    foreach (var item in dict)
    {
        type.GetProperty(item.Key).SetValue(result, item.Value, null);
    }
    return result;
}

private IDictionary<string, object> ObjectToDictionary<T>(T item)
    where T: class
{
    Type myObjectType = item.GetType();
    IDictionary<string, object> dict = new Dictionary<string, object>();
    var indexer = new object[0];
    PropertyInfo[] properties = myObjectType.GetProperties();
    foreach (var info in properties)
    {
        var value = info.GetValue(item, indexer);
        dict.Add(info.Name, value);
    }
    return dict;
}

यह नेस्टिंग का समर्थन नहीं करता है।
सीज़र

10

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

var appSettings =
  new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);

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


2
मुझे लगता है कि "सबसे अच्छी तरह से गुप्त" एक अकेला मौत मर गया। ऊपर कैसल डिक्शनरी एडेप्टर लिंक, साथ ही कैसलप्रोजेक्ट.ऑर्ग पर "डिक्शनरी एडाप्टर " के डाउनलोड लिंक सभी एक 404 पेज पर जाएँ :(
शिव

1
नहीं! यह अभी भी कैसल.कोर में है। मैंने लिंक तय कर दिया है।
गैसपार नागी

कैसल एक महान पुस्तकालय था जिसे किसी भी तरह से अनदेखा कर दिया गया
bikeman868

5

परावर्तन आपको एक वस्तु से एक शब्दकोश में गुणों पर पुनरावृति करके ले जा सकता है।

दूसरे तरीके से जाने के लिए, आपको C # में एक डायनेमिक एक्सपेंडेब्यूज (जो वास्तव में, पहले से ही IDfox से विरासत में मिला है, और ऐसा आपके लिए किया है) का उपयोग करना होगा, जब तक कि आप प्रविष्टियों के संग्रह से टाइप का अनुमान नहीं लगा सकते किसी तरह शब्दकोश।

इसलिए, यदि आप .NET 4.0 भूमि में हैं, तो एक ExpandoObject का उपयोग करें, अन्यथा आपको बहुत सारे काम करने हैं ...


4

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

private T ConvertDictionaryTo<T>(IDictionary<string, object> dictionary) where T : new()
{
    Type type = typeof (T);
    T ret = new T();

    foreach (var keyValue in dictionary)
    {
        type.GetProperty(keyValue.Key).SetValue(ret, keyValue.Value, null);
    }

    return ret;
}

यह आपका शब्दकोश लेता है और इसके माध्यम से छोरों और मूल्यों को निर्धारित करता है। आपको इसे बेहतर बनाना चाहिए लेकिन यह एक शुरुआत है। आपको इसे इस तरह से कॉल करना चाहिए:

SomeClass someClass = ConvertDictionaryTo<SomeClass>(a);

यदि आप "नया" जेनेरिक बाधा का उपयोग कर सकते हैं, तो आप किस एक्टीवेटर का उपयोग करना चाहते हैं? :)
मैटास फिडेमाइजर

@ मैटिस फेमेडाइज़र आप बिल्कुल सही हैं। मेरी गलती। उसे बदल दिया।
टर्बस

धन्यवाद उर भयानक, एक मुद्दा अगर someclass में कुछ गुण नहीं हैं जो शब्दकोश में हैं। यह केवल गुणों को सम्‍मिलित करना चाहिए, जो अभी सोचेसेल में मौजूद हैं और दूसरे को छोड़ते हैं, अब तक मैंने इसके लिए कोई बेहतर विकल्प पकड़ने की कोशिश की थी?
सुनील चौधरी

3
public class SimpleObjectDictionaryMapper<TObject>
{
    public static TObject GetObject(IDictionary<string, object> d)
    {
        PropertyInfo[] props = typeof(TObject).GetProperties();
        TObject res = Activator.CreateInstance<TObject>();
        for (int i = 0; i < props.Length; i++)
        {
            if (props[i].CanWrite && d.ContainsKey(props[i].Name))
            {
                props[i].SetValue(res, d[props[i].Name], null);
            }
        }
        return res;
    }

    public static IDictionary<string, object> GetDictionary(TObject o)
    {
        IDictionary<string, object> res = new Dictionary<string, object>();
        PropertyInfo[] props = typeof(TObject).GetProperties();
        for (int i = 0; i < props.Length; i++)
        {
            if (props[i].CanRead)
            {
                res.Add(props[i].Name, props[i].GetValue(o, null));
            }
        }
        return res;
    }
}

2

मैटिस फिडमाइज़र के उत्तर पर निर्माण, यहां एक संस्करण है जो स्ट्रिंग्स के अलावा ऑब्जेक्ट गुणों के लिए बाध्यकारी का समर्थन करता है।

using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace WebOpsApi.Shared.Helpers
{
    public static class MappingExtension
    {
        public static T ToObject<T>(this IDictionary<string, object> source)
            where T : class, new()
        {
            var someObject = new T();
            var someObjectType = someObject.GetType();

            foreach (var item in source)
            {
                var key = char.ToUpper(item.Key[0]) + item.Key.Substring(1);
                var targetProperty = someObjectType.GetProperty(key);


                if (targetProperty.PropertyType == typeof (string))
                {
                    targetProperty.SetValue(someObject, item.Value);
                }
                else
                {

                    var parseMethod = targetProperty.PropertyType.GetMethod("TryParse",
                        BindingFlags.Public | BindingFlags.Static, null,
                        new[] {typeof (string), targetProperty.PropertyType.MakeByRefType()}, null);

                    if (parseMethod != null)
                    {
                        var parameters = new[] { item.Value, null };
                        var success = (bool)parseMethod.Invoke(null, parameters);
                        if (success)
                        {
                            targetProperty.SetValue(someObject, parameters[1]);
                        }

                    }
                }
            }

            return someObject;
        }

        public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
        {
            return source.GetType().GetProperties(bindingAttr).ToDictionary
            (
                propInfo => propInfo.Name,
                propInfo => propInfo.GetValue(source, null)
            );
        }
    }
}

1

यदि आप Asp.Net MVC का उपयोग कर रहे हैं, तो एक नज़र डालें:

public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);

जो System.Web.Mvc.HtmlHelper क्लास पर एक स्थिर सार्वजनिक विधि है।


मैं इसका उपयोग नहीं करूंगा क्योंकि यह "_" को "-" के साथ बदल देता है। और आपको MVC की आवश्यकता है। शुद्ध रूटिंग क्लास का उपयोग करें: नए रूटवैल्यूडर (ऑब्जेक्टहेयर);
रेगिसबस

0
    public Dictionary<string, object> ToDictionary<T>(string key, T value)
    {
        try
        {
            var payload = new Dictionary<string, object>
            {
                { key, value }
            }; 
        } catch (Exception e)
        {
            return null;
        }
    }

    public T FromDictionary<T>(Dictionary<string, object> payload, string key)
    {
        try
        {
            JObject jObject = (JObject) payload[key];
            T t = jObject.ToObject<T>();
            return (t);
        }
        catch(Exception e) {
            return default(T);
        }
    }

हालांकि यह कोड प्रश्न का उत्तर दे सकता है, लेकिन यह कोड क्यों और / या इस प्रश्न के उत्तर के बारे में अतिरिक्त संदर्भ प्रदान करता है, इसके दीर्घकालिक मूल्य में सुधार करता है।
बाखो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.