简体   繁体   English

将对象映射到字典,反之亦然

[英]Mapping object to dictionary and vice versa

Are there any elegant quick way to map object to a dictionary and vice versa?是否有任何优雅的快速方法将对象映射到字典,反之亦然?

Example:示例:

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

becomes变成

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

Using some reflection and generics in two extension methods you can achieve that.在两种扩展方法中使用一些反射和泛型可以实现这一点。

Right, others did mostly the same solution, but this uses less reflection which is more performance-wise and way more readable:是的,其他人做了大致相同的解决方案,但这使用了更少的反射,这在性能方面更具可读性:

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

Convert the Dictionary to JSON string first with Newtonsoft.首先使用 Newtonsoft 将字典转换为 JSON 字符串。

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

Then deserialize the JSON string to your object然后将 JSON 字符串反序列化为您的对象

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

Seems reflection only help here.. I've done small example of converting object to dictionary and vise versa:似乎反射只在这里有帮助..我已经完成了将对象转换为字典的小例子,反之亦然:

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

I'd highly recommend the Castle DictionaryAdapter , easily one of that project's best-kept secrets.我强烈推荐Castle DictionaryAdapter ,它很容易成为该项目保存最完好的秘密之一。 You only need to define an interface with the properties you want, and in one line of code the adapter will generate an implementation, instantiate it, and synchronize its values with a dictionary you pass in. I use it to strongly-type my AppSettings in a web project:你只需要定义一个你想要的属性的接口,在一行代码中,适配器将生成一个实现,实例化它,并将它的值与你传入的字典同步。我用它来强输入我的 AppSettings一个网络项目:

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

Note that I did not need to create a class that implements IAppSettings - the adapter does that on the fly.请注意,我不需要创建一个实现 IAppSettings 的类 - 适配器会即时完成。 Also, although in this case I'm only reading, in theory if I were setting property values on appSettings, the adapter would keep the underlying dictionary in sync with those changes.此外,虽然在这种情况下我只是阅读,理论上如果我在 appSettings 上设置属性值,适配器将使底层字典与这些更改保持同步。

Reflection can take you from an object to a dictionary by iterating over the properties.反射可以通过迭代属性将您从对象带到字典。

To go the other way, you'll have to use a dynamic ExpandoObject (which, in fact, already inherits from IDictionary, and so has done this for you) in C#, unless you can infer the type from the collection of entries in the dictionary somehow. 反过来,您必须在 C# 中使用动态ExpandoObject (实际上,它已经从 IDictionary 继承,因此已经为您完成了这项工作),除非您可以从字典不知何故。

So, if you're in .NET 4.0 land, use an ExpandoObject, otherwise you've got a lot of work to do...因此,如果您在 .NET 4.0 领域,请使用 ExpandoObject,否则您有很多工作要做...

I think you should use reflection.我认为你应该使用反射。 Something like this:像这样的东西:

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

It takes your dictionary and loops through it and sets the values.它需要你的字典并循环遍历它并设置值。 You should make it better but it's a start.你应该让它变得更好,但这是一个开始。 You should call it like this:你应该这样称呼它:

SomeClass someClass = ConvertDictionaryTo<SomeClass>(a);

Building on Matías Fidemraizer's answer, here is a version that supports binding to object properties other than strings.基于 Matías Fidemraizer 的回答,这是一个支持绑定到字符串以外的对象属性的版本。

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

If you are using Asp.Net MVC, then take a look at:如果您使用的是 Asp.Net MVC,请查看:

public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);

which is a static public method on the System.Web.Mvc.HtmlHelper class.这是 System.Web.Mvc.HtmlHelper 类上的静态公共方法。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM