Existe-t-il un moyen rapide et élégant de mapper un objet à un dictionnaire et vice versa?
Exemple:
IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....
devient
SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
c#
.net
dictionary
reflection
mapping
Sawan
la source
la source
Réponses:
En utilisant une réflexion et des génériques dans deux méthodes d'extension, vous pouvez y parvenir.
D'accord, d'autres ont pour la plupart fait la même solution, mais cela utilise moins de réflexion, ce qui est plus performant et bien plus lisible:
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(); } }
la source
GetType()
n'est plus appeléesomeObject
pour chaque propriété dans la première méthode.Convertissez d'abord le dictionnaire en chaîne JSON avec Newtonsoft.
var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);
Désérialisez ensuite la chaîne JSON en votre objet
var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
la source
La réflexion ne semble aider ici. J'ai fait un petit exemple de conversion d'objet en dictionnaire et vice versa:
[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; }
la source
Je recommande vivement le Castle DictionaryAdapter , facilement l'un des secrets les mieux gardés de ce projet. Il vous suffit de définir une interface avec les propriétés souhaitées, et en une seule ligne de code, l'adaptateur générera une implémentation, l'instanciera et synchronisera ses valeurs avec un dictionnaire que vous transmettez. Je l'utilise pour taper fortement mes AppSettings dans un projet web:
var appSettings = new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);
Notez que je n'avais pas besoin de créer une classe qui implémente IAppSettings - l'adaptateur le fait à la volée. De plus, même si dans ce cas je ne fais que lire, en théorie, si je définissais des valeurs de propriété sur appSettings, l'adaptateur maintiendrait le dictionnaire sous-jacent synchronisé avec ces modifications.
la source
La réflexion peut vous faire passer d'un objet à un dictionnaire en itérant sur les propriétés.
Pour aller dans l'autre sens, vous devrez utiliser un ExpandoObject dynamique (qui, en fait, hérite déjà de IDictionary, et a donc fait cela pour vous) en C #, à moins que vous ne puissiez déduire le type de la collection d'entrées dans le dictionnaire en quelque sorte.
Donc, si vous êtes dans .NET 4.0, utilisez un ExpandoObject, sinon vous avez beaucoup de travail à faire ...
la source
Je pense que vous devriez utiliser la réflexion. Quelque chose comme ça:
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; }
Il prend votre dictionnaire, le parcourt en boucle et définit les valeurs. Vous devriez l'améliorer, mais c'est un début. Vous devriez l'appeler comme ceci:
la source
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; } }
la source
S'appuyant sur la réponse de Matías Fidemraizer, voici une version qui prend en charge la liaison aux propriétés d'objet autres que les chaînes.
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) ); } } }
la source
Si vous utilisez Asp.Net MVC, jetez un œil à:
public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);
qui est une méthode publique statique sur la classe System.Web.Mvc.HtmlHelper.
la source
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); } }
la source