c# - values - Asignar objeto al diccionario y viceversa
initialize dictionary c# (9)
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<AOCAdvancedSettings>(json);
¿Hay alguna forma elegante y rápida de asignar objetos a un diccionario y viceversa?
Ejemplo:
IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....
se convierte
SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
Creo que deberías usar el reflejo. Algo como esto:
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;
}
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<SomeClass>(a);
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 dinámico (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 ...
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<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;
}
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<IAppSettings>(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.
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.
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<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)
);
}
}
}
Usando algunos reflejos y genéricos 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<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;
}
}