我正在尝试确定使用以下序列化代理可能引起的问题,以便启用匿名函数/委托/ Lambda 的序列化。
// see http://msdn.microsoft.com/msdnmag/issues/02/09/net/#S3
class NonSerializableSurrogate : ISerializationSurrogate
{
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
foreach (FieldInfo f in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
info.AddValue(f.Name, f.GetValue(obj));
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context,
ISurrogateSelector selector)
{
foreach (FieldInfo f in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
f.SetValue(obj, info.GetValue(f.Name, f.FieldType));
return obj;
}
}
示例1 改编自 Counting Demo
我能想到的主要问题是匿名类是编译器内部细节,它的结构不能保证在 .NET Framework 的修订版本之间保持不变。我根据对迭代器类似问题的研究,相当确定这是个问题。
背景
我正在研究匿名函数的序列化。我原以为这不会起作用,但发现对于某些情况确实起作用。只要 Lambda 没有强制编译器生成匿名类,一切都很好。
如果编译器需要生成一个类来实现匿名函数,则会抛出 SerializationException 异常。这是因为编译器生成的类没有标记为可序列化。
示例
namespace Example
{
[Serializable]
class Other
{
public int Value;
}
[Serializable]
class Program
{
static void Main(string[] args)
{
MemoryStream m = new MemoryStream();
BinaryFormatter f = new BinaryFormatter();
// Example 1
Func<int> succeeds = () => 5;
f.Serialize(m, succeeds);
// Example 2
Other o = new Other();
Func<int> fails = () => o.Value;
f.Serialize(m, fails); // throws SerializationException - Type 'Example.Program+<>c__DisplayClass3' in Assembly 'Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
}
}
清单2
这类似于尝试序列化迭代器的问题,我在之前的搜索中找到了以下代码(请参见countingdemo)使用清单1中的代码和ISurrogateSelector,我能够成功地序列化和反序列化第二个失败示例。
目标
我有一个通过Web服务公开的系统。该系统具有复杂但小型的状态(许多对象,每个对象的属性不多)。该状态保存在ASP.NET Cache中,但也会序列化到SQL中的BLOB中以防缓存过期。一些对象需要在达到某些条件时执行任意“事件”。因此它们具有接受Action / Func对象的属性。人为的例子:
class Command
{
public Command(Action action, Func<bool> condition);
}
别处
void DoSomethingWithThing(Thing thing)
{
state = Store.GetCurrentState();
Command cmd = new Command(() => thing.Foo(), () => thing.IsReady())
state.Add(cmd);
Store.Save(state);
}