Adakah cara cepat yang elegan untuk memetakan objek ke kamus dan sebaliknya?
Contoh:
IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....
menjadi
SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
c#
.net
dictionary
reflection
mapping
Sawan
sumber
sumber
Jawaban:
Menggunakan beberapa refleksi dan generik dalam dua metode ekstensi, Anda dapat mencapainya.
Benar, sebagian besar orang lain melakukan solusi yang sama, tetapi ini menggunakan lebih sedikit refleksi yang lebih bijak dalam kinerja dan jauh lebih mudah dibaca:
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(); } }
sumber
GetType()
tidak dipanggilsomeObject
untuk setiap properti lagi di metode pertama.Konversikan Dictionary ke string JSON terlebih dahulu dengan Newtonsoft.
var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);
Kemudian deserialisasi string JSON ke objek Anda
var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
sumber
Sepertinya refleksi hanya membantu di sini .. Saya telah melakukan contoh kecil untuk mengubah objek ke kamus dan sebaliknya:
[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; }
sumber
Saya sangat merekomendasikan Castle DictionaryAdapter , salah satu rahasia proyek yang paling terjaga. Anda hanya perlu mendefinisikan antarmuka dengan properti yang Anda inginkan, dan dalam satu baris kode, adaptor akan menghasilkan implementasi, membuat instance-nya, dan menyinkronkan nilainya dengan kamus yang Anda berikan. Saya menggunakannya untuk mengetik AppSettings saya dengan kuat di sebuah proyek web:
var appSettings = new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);
Perhatikan bahwa saya tidak perlu membuat kelas yang mengimplementasikan IAppSettings - adaptor melakukannya dengan cepat. Juga, meskipun dalam kasus ini saya hanya membaca, secara teori jika saya menyetel nilai properti di appSettings, adaptor akan menjaga kamus yang mendasari tetap sinkron dengan perubahan tersebut.
sumber
Refleksi dapat membawa Anda dari sebuah objek ke kamus dengan melakukan iterasi pada properti.
Untuk pergi ke arah lain, Anda harus menggunakan ExpandoObject dinamis (yang sebenarnya sudah mewarisi dari IDictionary, dan telah melakukannya untuk Anda) di C #, kecuali Anda dapat menyimpulkan jenis dari kumpulan entri di kamus entah bagaimana.
Jadi, jika Anda berada di lahan .NET 4.0, gunakan ExpandoObject, jika tidak, Anda memiliki banyak pekerjaan yang harus dilakukan ...
sumber
Saya pikir Anda harus menggunakan refleksi. Sesuatu seperti ini:
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; }
Itu mengambil kamus Anda dan mengulanginya dan menetapkan nilainya. Anda harus membuatnya lebih baik tetapi ini adalah permulaan. Anda harus menyebutnya seperti ini:
sumber
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; } }
sumber
Berdasarkan jawaban Matías Fidemraizer, berikut adalah versi yang mendukung pengikatan ke properti objek selain string.
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) ); } } }
sumber
Jika Anda menggunakan Asp.Net MVC, lihat:
public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);
yang merupakan metode publik statis di kelas System.Web.Mvc.HtmlHelper.
sumber
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); } }
sumber