在C#中序列化匿名委托

Jos*_*gry 37 c# serialization .net-3.5

我试图确定使用以下序列化代理来启用匿名函数/委托/ lambdas的序列化可能导致什么问题.

// 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;
    }
}  
Run Code Online (Sandbox Code Playgroud)

清单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.
        }
    }
Run Code Online (Sandbox Code Playgroud)

清单2

这类似于尝试序列化迭代器的问题,我在之前的搜索中找到了以下代码(请参阅countingdemo)使用清单1中的代码和ISurrogateSelector,我能够成功序列化和反序列化第二个失败的示例.

目的

我有一个通过Web服务公开的系统.系统具有复杂但很小的状态(许多对象,而不是每个对象的很多属性).状态保存在ASP.NET缓存中,但在缓存过期的情况下也会序列化为SQL中的BLOB.某些对象在达到某些条件时需要执行任意"事件".因此,它们具有接受Action/Func对象的属性.举例:

    class Command
    {
        public Command(Action action, Func<bool> condition);
    }
Run Code Online (Sandbox Code Playgroud)

别的地方

    void DoSomethingWithThing(Thing thing)
    {
        state = Store.GetCurrentState();

        Command cmd = new Command(() => thing.Foo(), () => thing.IsReady())
        state.Add(cmd);

        Store.Save(state);
    }
Run Code Online (Sandbox Code Playgroud)

Amy*_*y B 5

某些对象需要执行任意"事件"才能达到某种条件.

这些事件多么武断?他们可以被计算,分配ID并映射到引用吗?

public class Command<T> where T : ISerializable
{
  T _target;
  int _actionId;
  int _conditionId;

  public Command<T>(T Target, int ActionId, int ConditionId)
  {
    _target = Target;
    _actionId = ActionId;
    _conditionId = ConditionId;
  }

  public bool FireRule()
  {
    Func<T, bool> theCondition = conditionMap.LookupCondition<T>(_conditionId)
    Action<T> theAction = actionMap.LookupAction<T>(_actionId);

    if (theCondition(_target))
    {
      theAction(_target);
      return true;
    }
    return false;
  }  
}
Run Code Online (Sandbox Code Playgroud)


小智 5

您是否看到我作为CountingDemo的后续文章撰写的这篇文章:http://dotnet.agilekiwi.com/blog/2007/12/update-on-persistent-iterators.html?不幸的是,微软已经确认他们可能会以一种可能导致问题的方式更改编译器详细信息(一天).(例如,当您更新到新编译器时,您将无法反序列化在旧(当前)编译器下保存的内容.)