2017-10-26 19 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がパブリックフィールドしか持たない場合はどこかに行くことができますが、プロパティは移動しません。 ExpandoObjectを使ってgetterとsetterを呼び出すことはできません。実際には、動的バインダ、つまりeo ["foo"] = 42のような文をDLR呼び出しに変換するのに役立つC#コンパイラの部分でうまく動作するように作られたクラスです。 JavascriptやPythonのような動的言語で一般的な文です。また、コンポーザー以外のパブリックメンバーを持たない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'の値は1 –

+0

@Scott Chamberlainになります。はい。あなたが正しいです。 – Valerii

+0

私の質問は、既存のオブジェクトの値に基づいてExpandoObjectを作成する方法を尋ねたので、これは問題ないと思います。 – Gigi

0

あなたはExpandoでオブジェクトにでPersonクラスを「変換」することはできません。ただし、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よくこれはハックの回避策のようなものです、私はエラーが発生したことに驚くことはありません。 –

関連する問題