【问题标题】:Can I serialize an ExpandoObject in .NET 4?我可以在 .NET 4 中序列化 ExpandoObject 吗?
【发布时间】:2011-01-31 16:48:47
【问题描述】:

我正在尝试使用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();
        }
    }
}

【问题讨论】:

  • 没有实现手动序列化例程,我倾向于说如果它没有标记Serializable 那么,不,很简单。

标签: c# .net serialization dynamic expandoobject


【解决方案1】:

我无法序列化 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? 有一块缺失的拼图来保持简单。

【讨论】:

  • 对回答我自己的问题有一些疑问,但似乎受到鼓励:meta.stackexchange.com/questions/9933/…
  • 是否也可以为自定义序列化库执行此操作?例如在我的情况下多功能序列化?
【解决方案2】:

ExpandoObject 实现IDictionary&lt;string, object&gt;,例如:

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,将其转换回字典并将属性写回?

【讨论】:

  • 如果输出必须是 XML 格式,那么 IDictionary&lt;,&gt; 不能用 XmlSerializer 序列化,但可以用 DataContractSerializer 序列化,尽管输出太冗长了。我个人认为其他答案中提到的 JsonFx 在序列化ExpandoObject 方面做得更好。
【解决方案3】:

回答可能有点晚了,但我使用 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)

【讨论】:

  • 美丽。 JsonWriter 为我节省了大量时间!如果有人需要,这里是 JsonFx 的 Git:github.com/jsonfx/jsonfx
  • 我试过这个。它非常适合序列化动态对象,但反序列化显示异常:Expected Object Property Name or end of object(Object Begin)。
  • 使用 JsonReader 和 Writer 而不是 Xml 来修复上述异常 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
  • 1970-01-01
  • 2017-05-10
  • 2018-06-21
  • 1970-01-01
  • 2012-07-31
  • 1970-01-01
相关资源
最近更新 更多