2011-01-31 4 views
27

私はSystem.Dynamic.ExpandoObjectを使用しようとしているので、実行時にプロパティを動的に作成することができます。後でこのオブジェクトのインスタンスを渡す必要があり、使用されるメカニズムにはシリアル化が必要です。もちろん.NET 4でExpandoObjectをシリアル化できますか?

私は私の動的オブジェクトをシリアル化しようとしたとき、私は例外を取得:

System.Runtime.Serialization.SerializationException was unhandled.

Type 'System.Dynamic.ExpandoObject' in Assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.

は私がExpandoObjectをシリアル化することはできますか?直列化可能な動的オブジェクトを作成する別の方法がありますか?おそらくDynamicObjectラッパーを使用していますか?

私は非常に単純なWindowsのエラーを複製する例をフォーム作成しました:

using System; 
using System.Windows.Forms; 
using System.IO; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Dynamic; 

namespace DynamicTest 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     {    
      dynamic dynamicContext = new ExpandoObject(); 
      dynamicContext.Greeting = "Hello"; 

      IFormatter formatter = new BinaryFormatter(); 
      Stream stream = new FileStream("MyFile.bin", FileMode.Create, 
              FileAccess.Write, FileShare.None); 
      formatter.Serialize(stream, dynamicContext); 
      stream.Close(); 
     } 
    } 
} 
+1

ショート

dim XMLwriter As New JsonFx.Xml.XmlWriter dim serializedExpando as string =XMLwriter.Write(obj) 

、デシリアライゼーションシリアライズルーチンでは、「シリアライザブル」と表示されていない場合は、単純に、シンプルではありません。 –

答えて

20

私はExpandoObjectをシリアル化できませんが、DynamicObjectを手動でシリアル化できます。ですから、DynamicObjectのTryGetMember/TrySetMemberメソッドを使用してISerializableを実装することで、私は本当に動的オブジェクトを直列化するという私の問題を解決できます。

私は私の簡単なテストアプリケーションに次のように実装しました:

using System; 
using System.Windows.Forms; 
using System.IO; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Collections.Generic; 
using System.Dynamic; 
using System.Security.Permissions; 

namespace DynamicTest 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     {    
      dynamic dynamicContext = new DynamicContext(); 
      dynamicContext.Greeting = "Hello"; 
      this.Text = dynamicContext.Greeting; 

      IFormatter formatter = new BinaryFormatter(); 
      Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None); 
      formatter.Serialize(stream, dynamicContext); 
      stream.Close(); 
     } 
    } 

    [Serializable] 
    public class DynamicContext : DynamicObject, ISerializable 
    { 
     private Dictionary<string, object> dynamicContext = new Dictionary<string, object>(); 

     public override bool TryGetMember(GetMemberBinder binder, out object result) 
     { 
      return (dynamicContext.TryGetValue(binder.Name, out result)); 
     } 

     public override bool TrySetMember(SetMemberBinder binder, object value) 
     { 
      dynamicContext.Add(binder.Name, value); 
      return true; 
     } 

     [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] 
     public virtual void GetObjectData(SerializationInfo info, StreamingContext context) 
     { 
      foreach (KeyValuePair<string, object> kvp in dynamicContext) 
      { 
       info.AddValue(kvp.Key, kvp.Value); 
      } 
     } 

     public DynamicContext() 
     { 
     } 

     protected DynamicContext(SerializationInfo info, StreamingContext context) 
     { 
      // TODO: validate inputs before deserializing. See http://msdn.microsoft.com/en-us/library/ty01x675(VS.80).aspx 
      foreach (SerializationEntry entry in info) 
      { 
       dynamicContext.Add(entry.Name, entry.Value); 
      } 
     } 

    } 
} 

Why does SerializationInfo not have TryGetValue methods?はそれをシンプルに保つために不足しているパズルのピースを持っていました。

+3

私自身の質問に答えることにいくつか疑問がありましたが、奨励されるようです:http://meta.stackexchange.com/questions/9933/is-there-a-convention-for-accepting-my-own-answer-to - 私自身の質問 –

9

ExpandoObjectIDictionary<string, object>、例えばを実装します。

class Test 
{ 
    static void Main() 
    { 
     dynamic e = new ExpandoObject(); 
     e.Name = "Hello"; 

     IDictionary<string, object> dict = (IDictionary<string, object>)e; 

     foreach (var key in dict.Keys) 
     { 
      Console.WriteLine(key); 
     } 

     dict.Add("Test", "Something"); 

     Console.WriteLine(e.Test); 

     Console.ReadKey(); 
    } 
} 

あなたは、ファイルへの辞書の内容を書くことができますデシリアライゼーションによって新しいExpandoObjectを作成し、辞書にキャストしてプロパティを書き戻しますか?

+0

出力がXMLでなければならない場合、 'IDictionary <,>'は[XmlSerializer](http://msdn.microsoft.com/EN-US/library/swxzdhc0.aspx)でシリアル化できませんが、 [DataContractSerializer](http://msdn.microsoft.com/en-US/library/ms405768.aspx)出力があまりにも冗長です。個人的には、JsonFxが他の答えで言及したことは、 'ExpandoObject'をシリアライズするより良い仕事だと思います。 – Mike

8

答えることはたぶん少し遅れたが、私はexpandoObjectsをシリアライズとデシリアライズするjsonFxを使用して、それは非常にうまく機能:

連載:マニュアルを実装する

dim XMLreader As New JsonFx.Xml.XmlReader 
Dim obj As ExpandoObject = XMLreader.Read(Str) 
+3

美しい。 JsonWriterはちょうど私の時間のトンを救った!誰かがそれを必要とするなら、JsonFxのためのGitはここにあります:https://github.com/jsonfx/jsonfx –

+1

私はこれを試しました。これは、動的オブジェクトをシリアライズするためには完全に機能しますが、直列化復元では、Expected Object Property Nameまたはオブジェクトの終わり(Object Begin)という例外が表示されます。 – sharmakeshav

+0

上記の例外を修正するには、Xmlの代わりにJsonReaderとWriterを使用してください:) – faztp12

関連する問題