31

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

もちろん、動的オブジェクトをシリアル化しようとすると、例外が発生します。

System.Runtime.Serialization.SerializationExceptionは処理されませんでした。

アセンブリ'System.Core、Version = 4.0.0.0、Culture = neutral、PublicKeyToken=b77a5c561934e089'に「System.Dynamic.ExpandoObject」と入力してもシリアル化可能としてマークされていません。

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();
        }
    }
}
4

3 に答える 3

23

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);
            }
        }

    }
}

そして、SerializationInfoにTryGetValueメソッドがないのはなぜですか?シンプルにするためにパズルのピースが欠けていました。

于 2011-01-31T23:29:40.273 に答える
11

ExpandoObject実装IDictionary<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を作成し、それを辞書にキャストして、プロパティを書き戻すことができますか?

于 2011-01-31T16:59:39.940 に答える
9

答えるのが少し遅いかもしれませんが、私はjsonFxを使用してexpandoObjectsをシリアル化および逆シリアル化し、非常にうまく機能します:

シリアル化:

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

デシリアライズ

dim XMLreader As New JsonFx.Xml.XmlReader
Dim obj As ExpandoObject = XMLreader.Read(Str)
于 2011-03-27T12:02:47.153 に答える