我可以在.NET 4中序列化ExpandoObject吗?

我正在尝试使用System.Dynamic.ExpandoObject因此我可以在运行时动态创建属性。 稍后,我需要传递此对象的实例,并且使用的机制需要序列化。

当然,当我尝试序列化我的动态对象时,我得到了exception:

System.Runtime.Serialization.SerializationException未处理。

在Assembly’System.Core中输入’System.Dynamic.ExpandoObject’,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089’未标记为可序列化。

我可以序列化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(); } } } 

我无法序列化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 dynamicContext = new Dictionary(); 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 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方法? 有一个缺少的拼图,以保持简单。

ExpandoObject实现IDictionary ,例如:

 class Test { static void Main() { dynamic e = new ExpandoObject(); e.Name = "Hello"; IDictionary dict = (IDictionary)e; foreach (var key in dict.Keys) { Console.WriteLine(key); } dict.Add("Test", "Something"); Console.WriteLine(e.Test); Console.ReadKey(); } } 

您可以将字典的内容写入文件,然后通过反序列化创建一个新的ExpandoObject,将其强制转换为字典并将属性写回?

可能有点迟,但我使用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)