당신은 "변환"할 수없는 Person
클래스를의 expando 개체에. 그러나 Person
을 포함하는 랩퍼 DynamicObject
을 작성하고 모든 필드를 전달할 수 있습니다.
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Reflection;
namespace SandboxConsole
{
public class ExpandoWrapper : DynamicObject
{
private readonly object _item;
private readonly Dictionary<string, PropertyInfo> _lookup = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCulture);
private readonly Dictionary<string, PropertyInfo> _ignoreCaseLookup = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCultureIgnoreCase);
private readonly Dictionary<string, Box> _lookupExtra = new Dictionary<string, Box>(StringComparer.InvariantCulture);
private readonly Dictionary<string, Box> _ignoreCaseLookupExtra = new Dictionary<string, Box>(StringComparer.InvariantCultureIgnoreCase);
private class Box
{
public Box(object item)
{
Item = item;
}
public object Item { get; }
}
public ExpandoWrapper(object item)
{
_item = item;
var itemType = item.GetType();
foreach (var propertyInfo in itemType.GetProperties())
{
_lookup.Add(propertyInfo.Name, propertyInfo);
_ignoreCaseLookup.Add(propertyInfo.Name, propertyInfo);
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
PropertyInfo lookup;
if (binder.IgnoreCase)
{
_ignoreCaseLookup.TryGetValue(binder.Name, out lookup);
}
else
{
_lookup.TryGetValue(binder.Name, out lookup);
}
if (lookup != null)
{
result = lookup.GetValue(_item);
return true;
}
Box box;
if (binder.IgnoreCase)
{
_ignoreCaseLookupExtra.TryGetValue(binder.Name, out box);
}
else
{
_lookupExtra.TryGetValue(binder.Name, out box);
}
if (box != null)
{
result = box.Item;
return true;
}
return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
PropertyInfo lookup;
if (binder.IgnoreCase)
{
_ignoreCaseLookup.TryGetValue(binder.Name, out lookup);
}
else
{
_lookup.TryGetValue(binder.Name, out lookup);
}
if (lookup != null)
{
lookup.SetValue(_item, value);
return true;
}
var box = new Box(value);
_ignoreCaseLookupExtra[binder.Name] = box;
_lookupExtra[binder.Name] = box;
return true;
}
}
}
사용 예
using System;
namespace SandboxConsole
{
class Program
{
static void Main(string[] args)
{
var person = new Person() {Id = 1};
dynamic wrapper = new ExpandoWrapper(person);
wrapper.Id = 2;
wrapper.NewField = "Foo";
Console.WriteLine(wrapper.Id);
Console.WriteLine(person.Id);
Console.WriteLine(wrapper.NewField);
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Telephone { get; set; }
}
}
아마 당신은 사전 <문자열, 개체> 만들기 사람-클래스에서 모든 속성을 포함하고 그것은 동적 객체로 변환 할 수 있습니다? https://stackoverflow.com/questions/15819720/dynamically-add-c-sharp-properties-at-runtime – Jompa234
@PanagiotisKanavos'dynamic' "마술처럼 객체를 확장 가능하게 만들지 않습니다"https://stackoverflow.com/a/36558165 – Gigi
실용적이지 않습니다. Person이 public 필드 만 가지고 있으면 속성을 얻을 수 있지만 속성은 no-go입니다. ExpandoObject를 통해 getter 및 setter를 호출 할 수 없습니다. 실제로 동적 바인더, 즉 eo [ "foo"] = 42와 같은 명령문을 DLR 호출로 변환하는 데 도움이되는 C# 컴파일러의 일부로 잘 작동하는 클래스입니다. Javascript 또는 Python과 같은 동적 언어에서 일반적으로 사용되는 문입니다. 또한 생성자 이외의 public 멤버가없는 ExpandoObject에서도 분명합니다. –