2017-10-26 1 views
0

ExpandoObject은 속성을 추가하여 처음부터 동적으로 개체를 만드는 데 사용할 수 있지만 이미 동적 인 C# 개체에서 시작하여 동일한 작업을 수행하는 방법을 아직 찾지 못했습니다. 있다.C# 개체를 어떻게 ExpandoObject로 변환합니까?

public class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Address { get; set; } 
    public string Telephone { get; set; } 
} 

내가 차라리에서 같은 일을 재건보다가, 이미이 내용에 따라 속성을 추가하거나 제거 할 수 있도록 ExpandoObject이 변환하고 싶습니다 :

는 예를 들어,이 사소한 클래스가 할퀴다. 이것이 가능한가?

편집 : 중복으로 표시된 질문은 분명히이 사본과 중복되지 않습니다.

+0

아마 당신은 사전 <문자열, 개체> 만들기 사람-클래스에서 모든 속성을 포함하고 그것은 동적 객체로 변환 할 수 있습니다? https://stackoverflow.com/questions/15819720/dynamically-add-c-sharp-properties-at-runtime – Jompa234

+0

@PanagiotisKanavos'dynamic' "마술처럼 객체를 확장 가능하게 만들지 않습니다"https://stackoverflow.com/a/36558165 – Gigi

+0

실용적이지 않습니다. Person이 public 필드 만 가지고 있으면 속성을 얻을 수 있지만 속성은 no-go입니다. ExpandoObject를 통해 getter 및 setter를 호출 할 수 없습니다. 실제로 동적 바인더, 즉 eo [ "foo"] = 42와 같은 명령문을 DLR 호출로 변환하는 데 도움이되는 C# 컴파일러의 일부로 잘 작동하는 클래스입니다. Javascript 또는 Python과 같은 동적 언어에서 일반적으로 사용되는 문입니다. 또한 생성자 이외의 public 멤버가없는 ExpandoObject에서도 분명합니다. –

답변

4

는 그것은 다음과 같이 할 수있다 :

var person = new Person { Id = 1, Name = "John Doe" }; 

var expando = new ExpandoObject(); 
var dictionary = (IDictionary<string, object>)expando; 

foreach (var property in person.GetType().GetProperties()) 
    dictionary.Add(property.Name, property.GetValue(person)); 
+0

이 솔루션에 대해 분명히하고자하는 한 가지 점은 Person을 expando 개체로 만들지 않고 Person의 속성을 새로운 expando 개체로 복사하는 것입니다. 'expando.Id = 2'를 실행하면'person.Id'의 값은 여전히 ​​@ –

+0

@ Scott Chamberlain이됩니다. 예. 당신 말이 맞아요. – Valerii

+0

내 질문은 기존 개체의 값을 기반으로 ExpandoObject를 만드는 방법을 묻는 질문이므로 괜찮다고 생각합니다. – Gigi

0

당신은 "변환"할 수없는 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; } 
    } 
} 
+0

나는 이런 식으로 생각했다. – Valerii

+0

'JsonConvert.SerializeObject (wrapper)'는이 예제에서'{}'가된다. – Suamere

+0

@Suamere 잘 이것은 일종의 해킹 해결 방법이며, 나는 오류가 발생하는 것에 놀라지 않습니다. –

관련 문제