Отображение объекта в словарь и наоборот
есть ли элегантный быстрый способ отображения объекта в словарь и наоборот?
пример:
IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....
становится
SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
10 ответов:
используя некоторые отражения и обобщения в двух методах расширения, вы можете добиться этого.
правильно, другие делали в основном то же самое решение, но это использует меньше отражения, которое более эффективно и более читаемо:
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(); } }
Кажется, отражение только поможет здесь.. Я сделал небольшой пример преобразования объекта в словарь и наоборот:
[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; }
Я очень рекомендую Замок DictionaryAdapter, легко один из самых охраняемых секретов этого проекта. Вам нужно только определить интерфейс со свойствами, которые вы хотите, и в одной строке кода адаптер будет генерировать реализацию, создавать ее экземпляр и синхронизировать ее значения со словарем, который вы передаете. Я использую его для строгого ввода моих приложений в веб-проекте:
var appSettings = new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);обратите внимание, что мне не нужно было создавать класс, который реализует IAppSettings-the адаптер делает это на лету. Кроме того, хотя в этом случае я только читаю, теоретически, если бы я устанавливал значения свойств в appSettings, адаптер будет синхронизировать базовый словарь с этими изменениями.
отражение может перенести вас из объекта в словарь, повторяя свойства.
чтобы пойти в другую сторону, вам придется использовать динамический ExpandoObject (который, по сути, уже наследует от IDictionary, и поэтому сделал это для вас) в C#, если вы не можете каким-то образом вывести тип из коллекции записей в словаре.
Итак, если вы находитесь в .NET 4.0 land, используйте ExpandoObject, иначе вам придется много работать...
Я думаю, что вы должны использовать отражение. Что-то вроде этого:
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);
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; } }
основываясь на ответе 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) ); } } }
сначала преобразуйте словарь в строку JSON с помощью Newtonsoft.
var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);затем десериализовать JSON-строку вашего объекта
var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
Если вы используете Asp.Net MVC, затем взгляните на:
public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);который является статическим открытым методом в системе.Сеть.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); } }
Comments