Asignar objeto al diccionario y viceversa

¿Hay alguna forma elegante y rápida de asignar objetos a un diccionario y viceversa?

Ejemplo:

IDictionary a = new Dictionary(); a["Id"]=1; a["Name"]="Ahmad"; // ..... 

se convierte

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

Usando algunos reflections y generics en dos métodos de extensión puedes lograr eso.

Correcto, otros hicieron la mayoría de las veces la misma solución, pero esto utiliza menos reflexión, que es más eficiente en cuanto a rendimiento y mucho más legible:

 public static class ObjectExtensions { public static T ToObject(this IDictionary 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 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 dictionary = new Dictionary(); dictionary.Add("Prop1", "hello world!"); dictionary.Add("Prop2", 3893); A someObject = dictionary.ToObject(); IDictionary objectBackToDictionary = someObject.AsDictionary(); } } 

Parece que la reflexión solo ayuda aquí … He hecho un pequeño ejemplo de conversión de objeto a diccionario y viceversa:

 [TestMethod] public void DictionaryTest() { var item = new SomeCLass { Id = "1", Name = "name1" }; IDictionary dict = ObjectToDictionary(item); var obj = ObjectFromDictionary(dict); } private T ObjectFromDictionary(IDictionary 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 ObjectToDictionary(T item) where T: class { Type myObjectType = item.GetType(); IDictionary dict = new Dictionary(); 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; } 

Recomiendo encarecidamente el Castle DictionaryAdapter , uno de los secretos mejor guardados de ese proyecto. Solo necesita definir una interfaz con las propiedades que desea, y en una línea de código, el adaptador generará una implementación, lo instanciará y sincronizará sus valores con un diccionario que pase. Lo uso para escribir con fuerza mis AppSettings en un proyecto web:

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

Tenga en cuenta que no necesité crear una clase que implemente IAppSettings, el adaptador lo hace sobre la marcha. Además, aunque en este caso solo estoy leyendo, en teoría, si estuviera configurando valores de propiedad en appSettings, el adaptador mantendría el diccionario subyacente sincronizado con esos cambios.

La reflexión puede llevarlo de un objeto a un diccionario al iterar sobre las propiedades.

Para ir por el otro lado, tendrá que usar un ExpandoObject dynamic (que, de hecho, ya hereda de IDictionary, y lo ha hecho por usted) en C #, a menos que pueda inferir el tipo de la colección de entradas en el diccionario de alguna manera.

Entonces, si estás en .NET 4.0 land, usa un ExpandoObject, de lo contrario, tienes mucho trabajo por hacer …

Creo que deberías usar el reflection. Algo como esto:

 private T ConvertDictionaryTo(IDictionary 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; } 

Toma su diccionario y lo recorre y establece los valores. Deberías hacerlo mejor, pero es un comienzo. Deberías llamarlo así:

 SomeClass someClass = ConvertDictionaryTo(a); 
 public class SimpleObjectDictionaryMapper { public static TObject GetObject(IDictionary d) { PropertyInfo[] props = typeof(TObject).GetProperties(); TObject res = Activator.CreateInstance(); 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 GetDictionary(TObject o) { IDictionary res = new Dictionary(); 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; } } 

Sobre la base de la respuesta de Matías Fidemraizer, aquí hay una versión que admite el enlace a propiedades de objetos que no sean cadenas.

 using System.Collections.Generic; using System.Linq; using System.Reflection; namespace WebOpsApi.Shared.Helpers { public static class MappingExtension { public static T ToObject(this IDictionary 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 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) ); } } } 

Convierta el diccionario a cadena JSON primero con Newtonsoft.

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

Luego deserialice la cadena JSON a su objeto

 var myobject = JsonConvert.DeserializeObject(json); 

Si está utilizando Asp.Net MVC, eche un vistazo a:

 public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes); 

que es un método público estático en la clase System.Web.Mvc.HtmlHelper.

  public Dictionary ToDictionary(string key, T value) { try { var payload = new Dictionary { { key, value } }; } catch (Exception e) { return null; } } public T FromDictionary(Dictionary payload, string key) { try { JObject jObject = (JObject) payload[key]; T t = jObject.ToObject(); return (t); } catch(Exception e) { return default(T); } }