객체를 사전에 매핑하는 우아한 빠른 방법이 있습니까?
예:
IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....
된다
SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
객체를 사전에 매핑하는 우아한 빠른 방법이 있습니까?
IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....
된다
SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
답변:
두 가지 확장 방법에서 일부 리플렉션과 제네릭을 사용하면이를 달성 할 수 있습니다.
맞습니다, 다른 사람들은 대부분 동일한 솔루션을 수행했지만 이것은 성능면에서 더 읽기 쉽고 더 읽기 쉬운 반사를 덜 사용합니다.
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();
}
}
GetType()
에 someObject
대해 호출되지 않는지 확인합니다 .
Newtonsoft를 사용하여 먼저 사전을 JSON 문자열로 변환하십시오.
var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);
그런 다음 JSON 문자열을 객체로 역 직렬화합니다.
var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
리플렉션은 여기서 만 도움이되는 것 같습니다. 저는 객체를 사전으로 변환하는 작은 예제를 수행했으며 그 반대도 마찬가지입니다.
[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;
}
이 프로젝트에서 가장 잘 보존 된 비밀 중 하나 인 Castle DictionaryAdapter를 적극 추천합니다 . 원하는 속성으로 인터페이스를 정의하기 만하면됩니다. 한 줄의 코드에서 어댑터는 구현을 생성하고 인스턴스화하고 전달한 사전과 해당 값을 동기화합니다.이를 사용하여 내 AppSettings를 웹 프로젝트 :
var appSettings =
new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);
IAppSettings를 구현하는 클래스를 만들 필요가 없었습니다. 어댑터가 즉시 수행합니다. 또한이 경우에는 읽기만하고 있지만 이론적으로 appSettings에서 속성 값을 설정하는 경우 어댑터는 기본 사전을 해당 변경 사항과 동기화 상태로 유지합니다.
리플렉션은 속성을 반복하여 객체에서 사전으로 이동할 수 있습니다.
다른 방법으로 이동하려면 C #에서 동적 ExpandoObject (실제로는 이미 IDictionary에서 상속 하므로이 작업을 수행했습니다)를 사용해야합니다. 어떻게 든 사전.
따라서 .NET 4.0 땅에 있다면 ExpandoObject를 사용하십시오. 그렇지 않으면 할 일이 많습니다.
반사를 사용해야한다고 생각합니다. 이 같은:
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;
}
사전을 가져 와서 반복하고 값을 설정합니다. 더 나아 져야하지만 시작입니다. 다음과 같이 호출해야합니다.
SomeClass someClass = ConvertDictionaryTo<SomeClass>(a);
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;
}
}
Matías Fidemraizer의 답변을 바탕으로 문자열 이외의 객체 속성에 대한 바인딩을 지원하는 버전이 있습니다.
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)
);
}
}
}
Asp.Net MVC를 사용하는 경우 다음을 살펴보십시오.
public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);
System.Web.Mvc.HtmlHelper 클래스의 정적 공용 메서드입니다.
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);
}
}