অভিধানে এবং এর বিপরীতে ম্যাপিং অবজেক্ট


91

অভিধান এবং তদ্বিপরীতকে অবজেক্ট ম্যাপ করার জন্য কি কোনও দুর্দান্ত দ্রুত উপায় আছে?

উদাহরণ:

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

হয়ে যায়

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

প্রোটোবুফের মতো কোড-প্রজন্মের থেকে দ্রুততম উপায় হবে ... যতবার সম্ভব প্রতিচ্ছবি এড়াতে আমি অভিব্যক্তি গাছ ব্যবহার করেছি
Konrad

নীচের সমস্ত স্ব-কোডেড উত্তরগুলি গভীর রূপান্তর সমর্থন করে না এবং বাস্তব জীবনের অ্যাপ্লিকেশনগুলিতে কাজ করবে না। উপার্জনকারীদের পরামর্শ অনুসারে নিউটোনসফ্টের মতো আপনার কিছু লাইব্রেরি ব্যবহার করা উচিত
সিজার

উত্তর:


175

দুটি এক্সটেনশন পদ্ধতিতে কিছু প্রতিবিম্ব এবং জেনেরিক ব্যবহার করে আপনি এটি অর্জন করতে পারেন।

ঠিক আছে, অন্যরা বেশিরভাগই একই সমাধান করেছিলেন তবে এটি কম প্রতিবিম্ব ব্যবহার করে যা বেশি কার্য সম্পাদন-ভিত্তিক এবং আরও পাঠযোগ্য able

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

আমি বাস্তবায়ন পছন্দ করি, আমি আসলে এটি ব্যবহার শুরু করেছি, তবে পারফরম্যান্স সম্পর্কে আপনার কোনও প্রতিক্রিয়া আছে? আমি জানি যে প্রতিচ্ছবি সবচেয়ে বড় হয় না যখন এটি অভিনয় হয়? যদি আপনার কোন মন্তব্য আছে?
নোলিমিত

@ নোলিমিট আসলে আমি এর আসল পারফরম্যান্সটি জানি না, তবে আমার ধারণা এটি খারাপ নয় (অবশ্যই প্রতিচ্ছবি এড়ানোর চেয়ে খারাপ, অবশ্যই ...)। আসলে, বিকল্প কি? প্রকল্পগুলির প্রয়োজনীয়তার উপর নির্ভর করে, সম্ভবত অন্যান্য বিকল্প রয়েছে, যেমন ডায়নামিক টাইপিং যা প্রতিবিম্বের চেয়ে অনেক দ্রুত ... ব্যবহার করেন! :)
Matías Fidemraizer

আমার ক্ষেত্রে বিকল্পটি অ্যাসাইনমেন্ট দ্বারা অবজেক্টটি তৈরি করার মতোই সহজ, তবে আমি কোনও অবজেক্ট তৈরির জন্য একটি ঝরঝরে এখনও সস্তা ব্যয়টির সন্ধান করছি। যে বলেন না, আমি খুঁজে পেয়েছি এই যা আমার মানে এটি অত্যন্ত ব্যয়বহুল কোড যে টুকরা ব্যবহার করতে নয়।
নোলিমিত

@ নোলিমিট হ্যাঁ, মনে হচ্ছে কোনও সমস্যা নেই। এটি কেবলমাত্র প্রয়োজনীয় সমস্যার জন্য সঠিক সরঞ্জামটি ব্যবহার করার বিষয়ে: ডি আপনার ক্ষেত্রে এটি মনোযোগের মতো কাজ করা উচিত। আমি বিশ্বাস করি যে আমি কোডটিতে এখনও কিছু টিউন করতে পারি!
Matías Fidemraizer

@ নোলিমিট চেক করুন যে এখন প্রথম পদ্ধতিতে প্রতিটি সম্পত্তির জন্য আর GetType()ডাকা হয় নি someObject
Matías Fidemraizer

31

ডিকশনারিকে জেএসএন স্ট্রিংয়ে প্রথমে নিউটনসফট দিয়ে রূপান্তর করুন।

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

তারপরে আপনার অবজেক্টে জেএসওএন স্ট্রিংকে ডিসিজায়ালাইজ করুন

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

4
সহজ এবং সৃজনশীল!
কমলপ্রীত

4
সাবধানতার সাথে এই পদ্ধতির ব্যবহার করুন। এটি যদি অনেকগুলি (শত) অভিধানের জন্য ব্যবহৃত হয় তবে এটি আপনার অ্যাপ্লিকেশনটিকে ভুগিয়ে তুলবে।
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

আমি অত্যন্ত ক্যাসল ডিকশনারি অ্যাডাপ্টার সুপারিশ করতাম , সহজেই সেই প্রকল্পের সেরা রক্ষিত রহস্যগুলির মধ্যে একটি। আপনাকে কেবল নিজের পছন্দসই বৈশিষ্ট্যগুলির সাথে ইন্টারফেসটি সংজ্ঞায়িত করতে হবে এবং কোডের একটি লাইনে অ্যাডাপ্টার একটি প্রয়োগকরণ তৈরি করবে, এটি ইনস্ট্যানিয়েট করবে এবং আপনি যে অভিধানটি পাশ করবেন তার সাথে এর মানগুলি সিঙ্ক্রোনাইজ করবে I একটি ওয়েব প্রকল্প:

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

নোট করুন যে আমার এমন কোনও ক্লাস তৈরি করার দরকার নেই যা আইএপসেটেটিংগুলি প্রয়োগ করে - অ্যাডাপ্টারটি ফ্লাইতে করে। এছাড়াও, যদিও এই ক্ষেত্রে আমি কেবল পঠন করছি, তাত্ত্বিকভাবে যদি আমি অ্যাপসেটেটিংয়ের উপর সম্পত্তি মানগুলি সেট করে থাকি তবে অ্যাডাপ্টার অন্তর্নিহিত অভিধানটিকে সেই পরিবর্তনগুলির সাথে সিঙ্ক করে রাখে।


4
আমার ধারণা, "বেস্ট-কিপড সিক্রেট" মারা গেলেন একাকী মৃত্যু। উপরের ক্যাসল ডিকশনারি অ্যাডাপ্টার লিঙ্কটি, পাশাপাশি ক্যাসলপ্রজেক্ট.ওরে " অভিধানআডাপ্টার " এর জন্য ডাউনলোড লিঙ্কগুলি একটি 404 পৃষ্ঠাতে চলেছে :(
শিব

4
না! এটি এখনও ক্যাসেল.কোরে রয়েছে। আমি লিঙ্কটি স্থির করেছি।
গ্যাসপাড় নাগি

ক্যাসেল একটি দুর্দান্ত গ্রন্থাগার যা কোনওভাবে উপেক্ষা করা হয়েছিল
বাইকম্যান 868

5

প্রতিচ্ছবি বৈশিষ্ট্যগুলি পুনরাবৃত্তি করে আপনাকে কোনও অবজেক্ট থেকে অভিধানে নিয়ে যেতে পারে।

অন্য উপায়ে যেতে, আপনাকে একটি ডায়নামিক এক্সপেন্ডোঅবজেক্ট ব্যবহার করতে হবে সি # তে (যা বাস্তবে আইডোরিয়াস থেকে ইতিমধ্যে উত্তরাধিকার সূত্রে প্রাপ্ত হয়েছে, এবং এটি আপনার জন্য এটি করেছে) ব্যবহার করতে হবে, যদি না আপনি প্রবেশের সংগ্রহগুলি থেকে টাইপটি অনুমান করতে না পারেন অভিধান একরকম।

সুতরাং, যদি আপনি .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);

আপনি যদি "নতুন" জেনেরিক সীমাবদ্ধতাটি ব্যবহার করতে পারেন তবে আপনি অ্যাক্টিভেটরটি কী ব্যবহার করতে চান? :)
Matías Fidemraizer

@ মাতাস ফিডেম্রেজার আপনি একেবারে ঠিক বলেছেন। আমার ভুল. এটা পরিবর্তন।
তুরবাস

ধন্যবাদ আপনার দারুণ, একটি বিষয় যদি কিছু শ্রেণিতে অভিধানে থাকে এমন কিছু বৈশিষ্ট্য না থাকে। এটি কেবল মিলিত হওয়া উচিত বৈশিষ্ট্যগুলি কিছু ধীরে ধীরে বিদ্যমান এবং অন্যটি এড়িয়ে যান, এখন পর্যন্ত আমি কি এর জন্য আরও ভাল বিকল্প ধরার চেষ্টা করেছি?
সুনীল চৌধুরী চৌধুরী

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.Html সহায়তা বিভাগে একটি স্থিতিশীল পাবলিক পদ্ধতি।


"_" এর পরিবর্তে "-" এর পরিবর্তে আমি এটি ব্যবহার করব না। এবং আপনার এমভিসি দরকার। খাঁটি রাউটিং ক্লাসটি ব্যবহার করুন: নতুন রুটভ্যালুড অভিধান (অবজেক্টহিয়ার);
regisbsb

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

এই কোডটি প্রশ্নের উত্তর দিতে পারে, কেন এবং / অথবা এই কোডটির প্রশ্নের উত্তর কীভাবে তার দীর্ঘমেয়াদী মানকে উন্নত করে তা সম্পর্কিত অতিরিক্ত প্রসঙ্গ সরবরাহ করে।
বৈখো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.