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

Saw*_*wan 79 .net c# mapping dictionary idictionary

是否有任何优雅的快速方法将对象映射到字典,反之亦然?

例:

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

SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
Run Code Online (Sandbox Code Playgroud)

Mat*_*zer 162

在两种扩展方法中使用一些反射和泛型可以实现这一点.

是的,其他人做了大多数相同的解决方案,但这使用较少的反射,这在性能方面更具有可读性:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案不适用于匿名对象(例如,当您没有要转换的类型时),请参阅/sf/answers/531768821/ (2认同)

lea*_*tes 19

首先使用Newtonsoft将Dictionary转换为JSON字符串。

var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);
Run Code Online (Sandbox Code Playgroud)

然后将JSON字符串反序列化为您的对象

var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
Run Code Online (Sandbox Code Playgroud)

  • 请谨慎使用此方法。如果用于许多(数百个)词典,它将使您的应用程序陷入困境。 (2认同)

And*_*ich 11

似乎反射只有帮助.我已经完成了将对象转换为字典的小例子,反之亦然:

[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;
}
Run Code Online (Sandbox Code Playgroud)


Tod*_*ier 10

我强烈推荐Castle DictionaryAdapter,这是该项目保存最好的秘密之一.您只需要定义一个具有所需属性的接口,并在一行代码中,适配器将生成一个实现,实例化它,并将其值与您传入的字典同步.我用它来强类型我的AppSettings in一个网络项目:

var appSettings =
  new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);
Run Code Online (Sandbox Code Playgroud)

请注意,我不需要创建一个实现IAppSettings的类 - 适配器即时执行.此外,虽然在这种情况下我只是阅读,理论上如果我在appSettings上设置属性值,适配器将使基础字典与这些更改保持同步.

  • 我猜这个"最保密的秘密"死于孤独的死亡.上面的Castle DictionaryAdapter链接,以及http://www.castleproject.org/上"DictionaryAdapter"的下载链接都转到404页面:( (2认同)

Tur*_*Bas 6

我认为你应该使用反射。像这样的东西:

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;
}
Run Code Online (Sandbox Code Playgroud)

它获取你的字典并循环它并设置值。你应该让它变得更好,但这只是一个开始。你应该这样称呼它:

SomeClass someClass = ConvertDictionaryTo<SomeClass>(a);
Run Code Online (Sandbox Code Playgroud)


Mas*_*sif 5

通过迭代属性,反射可以将您从对象带到字典.

换句话说,你必须在C#中使用动态的ExpandoObject(事实上​​,它已经从IDictionary继承了,所以已经为你完成了这个),除非你可以从中收集条目集合中的类型.字典不知何故.

所以,如果你在.NET 4.0中,请使用ExpandoObject,否则你需要做很多工作......


小智 5

基于 Mat\xc3\xadas Fidemraizer 的答案,这里是一个支持绑定到字符串以外的对象属性的版本。

\n
using System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace WebOpsApi.Shared.Helpers\n{\n    public static class MappingExtension\n    {\n        public static T ToObject<T>(this IDictionary<string, object> source)\n            where T : class, new()\n        {\n            var someObject = new T();\n            var someObjectType = someObject.GetType();\n\n            foreach (var item in source)\n            {\n                var key = char.ToUpper(item.Key[0]) + item.Key.Substring(1);\n                var targetProperty = someObjectType.GetProperty(key);\n\n                //edited this line\n                if (targetProperty.PropertyType == item.Value.GetType())\n                {\n                    targetProperty.SetValue(someObject, item.Value);\n                }\n                else\n                {\n\n                    var parseMethod = targetProperty.PropertyType.GetMethod("TryParse",\n                        BindingFlags.Public | BindingFlags.Static, null,\n                        new[] {typeof (string), targetProperty.PropertyType.MakeByRefType()}, null);\n                    \n                    if (parseMethod != null)\n                    {\n                        var parameters = new[] { item.Value, null };\n                        var success = (bool)parseMethod.Invoke(null, parameters);\n                        if (success)\n                        {\n                            targetProperty.SetValue(someObject, parameters[1]);\n                        }\n\n                    }\n                }\n            }\n\n            return someObject;\n        }\n\n        public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)\n        {\n            return source.GetType().GetProperties(bindingAttr).ToDictionary\n            (\n                propInfo => propInfo.Name,\n                propInfo => propInfo.GetValue(source, null)\n            );\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n