Mapping object to dictionary and vice versa

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

例如:

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";
// ..........
169769 次浏览

反射可以通过迭代属性将您从一个对象带到一个字典。

另一方面,您必须在 C # 中使用动态 扩展对象(实际上,它已经继承了 IDictionary,因此已经为您做到了这一点) ,除非您能够以某种方式从字典中的条目集合推断出类型。

因此,如果您处于.NET 4.0的领域,那么使用一个 expandObject,否则您将有许多工作要做..。

似乎反射只在这里有帮助... ... 我已经做了一个把对象转换成字典的小例子,反之亦然:

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

我觉得你应该用反射,像这样:

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

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

没错,其他人大多采用了相同的解决方案,但是这种方法使用了更少的反射,从性能和可读性方面来说都更好:

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

我强烈推荐 Castle DictionaryAdapter,它很容易成为这个项目最保守的秘密之一。您只需定义一个具有所需属性的接口,在一行代码中,适配器将生成一个实现,实例化它,并将其值与您传入的字典同步。我使用它在一个 Web 项目中强类型化我的 AppSettings:

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

注意,我不需要创建一个实现 IAppSettings 的类——适配器会动态地实现它。另外,虽然在本例中我只是在阅读,但是从理论上讲,如果我在 appSettings 上设置属性值,适配器将使底层字典与这些更改保持同步。

如果你正在使用 Asp.Net MVC,那么看看:

public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);

它是 System.Web.Mvc.HtmlHelper 类上的静态公共方法。

基于 Matias 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);


//edited this line
if (targetProperty.PropertyType == item.Value.GetType())
{
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)
);
}
}
}

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

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

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

var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
    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);
}
}