Mappage d’object au dictionnaire et vice versa

Existe-t-il un moyen rapide et élégant de mapper un object vers un dictionnaire et vice versa?

Exemple:

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

devient

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

En utilisant une reflection et des génériques dans deux méthodes d’extension, vous pouvez y parvenir.

Bien sûr, d’autres ont fait la même solution, mais cela utilise moins de reflection, ce qui est plus performant et plus lisible:

 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 ssortingng Prop1 { get; set; } public int Prop2 { get; set; } } class Program { static void Main(ssortingng[] args) { Dictionary dictionary = new Dictionary(); dictionary.Add("Prop1", "hello world!"); dictionary.Add("Prop2", 3893); A someObject = dictionary.ToObject(); IDictionary objectBackToDictionary = someObject.AsDictionary(); } } 

Semble que la reflection aide seulement ici .. J’ai fait un petit exemple de conversion d’object en dictionnaire et vice versa:

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

Je recommande fortement 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 dans une 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 saisir fortement mes AppSettings dans un projet web:

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

Notez que je n’ai pas eu besoin de créer une classe qui implémente IAppSettings – l’adaptateur le fait à la volée. Aussi, bien que 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 en phase avec ces modifications.

La reflection peut vous amener d’un object à un dictionnaire en itérant sur les propriétés.

Pour aller dans l’autre sens, vous devrez utiliser un ExpandoObject dynamic (qui, en fait, hérite déjà de IDictionary, et a donc fait cela pour vous) en C #, sauf si vous pouvez déduire le type de la collection d’entrées du dictionnaire en quelque sorte.

Donc, si vous êtes dans .NET 4.0, utilisez un ExpandoObject, sinon vous avez beaucoup de travail à faire …

Je pense que vous devriez utiliser la reflection. Quelque chose comme ça:

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

Il prend votre dictionnaire et le parcourt en boucle et définit les valeurs. Vous devriez le rendre meilleur mais c’est un début. Vous devriez l’appeler comme ceci:

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

S’appuyant sur la réponse de Matías Fidemraizer, voici une version qui prend en charge la liaison à des propriétés d’object autres que des chaînes.

 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.Subssortingng(1); var targetProperty = someObjectType.GetProperty(key); if (targetProperty.PropertyType == typeof (ssortingng)) { targetProperty.SetValue(someObject, item.Value); } else { var parseMethod = targetProperty.PropertyType.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, null, new[] {typeof (ssortingng), 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) ); } } } 

Convertissez le dictionnaire en chaîne JSON avec Newtonsoft.

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

Puis désérialiser la chaîne JSON sur votre object

 var myobject = JsonConvert.DeserializeObject(json); 

Si vous utilisez Asp.Net MVC, consultez:

 public static RouteValueDictionary AnonymousObjectToHtmlAtsortingbutes(object htmlAtsortingbutes); 

qui est une méthode publique statique sur la classe System.Web.Mvc.HtmlHelper.

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