C# 在C中序列化匿名委托#

C# 在C中序列化匿名委托#,c#,.net-3.5,serialization,C#,.net 3.5,Serialization,我试图确定使用以下序列化代理来启用匿名函数/delegate/lambda的序列化可能会导致哪些问题 // see http://msdn.microsoft.com/msdnmag/issues/02/09/net/#S3 class NonSerializableSurrogate : ISerializationSurrogate { public void GetObjectData(object obj, SerializationInfo info, StreamingCon

我试图确定使用以下序列化代理来启用匿名函数/delegate/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改编自

我能想到的主要问题可能是,匿名类是一个内部编译器细节,它的结构不能保证在.NET Framework的修订之间保持不变。基于我对迭代器的类似问题的研究,我相当肯定这是一种情况

背景 我正在调查匿名函数的序列化。我原以为这不管用,但发现在某些情况下管用了。只要lambda没有强制编译器生成一个匿名类,一切都正常

如果编译器需要生成的类来实现匿名函数,则会引发SerializationException。这是因为编译器生成的类未标记为可序列化

例子
序列化委托的整个想法是非常危险的。现在,表达式可能有意义,但即使这样也很难表达——尽管动态LINQ示例在某种程度上允许基于文本的表达式形式

对于序列化委托,您到底想做什么?我真的不认为这是个好主意

有些对象需要执行任意“事件”,达到某种条件

这些事件到底有多武断?它们是否可以计数、分配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;
  }  
}
公共类命令,其中T:ISerializable
{
T_目标;
int_actionId;
int_conditionId;
公共命令(T目标、int ActionId、int ConditionId)
{
_目标=目标;
_actionId=actionId;
_条件ID=条件ID;
}
公共图书馆防火规则()
{
Func theCondition=conditionMap.LookupCondition(_conditionId)
Action theAction=actionMap.LookupAction(\u actionId);
如果(条件(_目标))
{
行动(_目标);
返回true;
}
返回false;
}  
}

函数映射将阻止我在操作/条件中使用本地状态。解决这个问题的唯一方法是为每个需要附加状态的函数创建一个类

这就是C#编译器使用匿名函数自动为我做的事情。我的问题是这些编译器类的序列化

        Other o = FromSomeWhere();
        Thing t = OtherPlace();
        target.OnWhatever = () => t.DoFoo() + o.DoBar();
        target.Save();c
尝试序列化将失败。由于此状态是本地状态,因此在尝试设置映射时会出现问题。相反,我必须声明如下内容:

[Serializable]
abstract class Command<T>
{
    public abstract T Run();
}

class DoFooBar : Command<int>
{
    public Other Other { get; set; }
    public Thing Thing { get; set; }

    public override int Run()
    {
        return Thing.DoFoo() + Other.DoBar(); 
    }
}
        DoFooBar cmd = new DoFooBar();
        cmd.Other = FromSomewhere();
        cmd.Thing = OtherPlace();

        target.OnWhatever = cmd.Run;

        target.Save();
本质上,这意味着手动执行C#编译器为我自动执行的操作

由于此状态是本地状态,因此在尝试设置映射时会出现问题

对于序列化,本地州不会出现完全相同的问题吗

假设编译器和框架允许这样做:

Other o = FromSomeWhere();
Thing t = OtherPlace();
target.OnWhatever = () => t.DoFoo() + o.DoBar();
target.Save();
我想t和o也必须序列化。方法没有状态,实例有

稍后,反序列化目标。你没有新的t和o的副本吗?这些副本不会与原始t和o的任何更改不同步吗

另外:您的手动示例不能这样称呼吗

Other o = FromSomeWhere();
Thing t = OtherPlace();
target.OnWhatever = new DoFooBar() {Other = o, Thing = t} .Run;
target.Save();

你看到我写的这篇文章了吗?它是作为CountingDemo的后续内容:?不幸的是,微软已经确认,他们可能会(某一天)更改编译器的详细信息,这可能会导致问题。(例如,当您更新到新的编译器时,您将无法反序列化您在旧(当前)编译器下保存的内容。)

我对此不是100%,但我相信,如果您希望将委托或某些代码“保存”到数据库中,并且可以相当动态,您需要做的是创建一个表达式,然后可以将表达式编译成Func


我编辑了我的问题,添加了一个目标部分。我也有一种普遍的“感觉”,这是有风险的,但没有很多具体的理由来解释为什么这是有风险的。我写下了我关于使用行动/条件图的问题。投票支持你的答案,因为它至少提供了一种选择。我希望“t”和“o”被序列化。当状态被反序列化(从数据库中)时,旧对象将消失,不再存在于内存中,因此冲突不是问题。我猜这基本上就是我的答案。必须注意编译器的更改,这样我才不会丢失序列化数据。+1他们确实更改了它,我们被它咬了一口。我把这个答案贴在上面:Other o=new Other();表达式失败=()=>o.值;f、 序列化(m,失败);//再次抛出序列化异常!
        DoFooBar cmd = new DoFooBar();
        cmd.Other = FromSomewhere();
        cmd.Thing = OtherPlace();

        target.OnWhatever = cmd.Run;

        target.Save();
Other o = FromSomeWhere();
Thing t = OtherPlace();
target.OnWhatever = () => t.DoFoo() + o.DoBar();
target.Save();
Other o = FromSomeWhere();
Thing t = OtherPlace();
target.OnWhatever = new DoFooBar() {Other = o, Thing = t} .Run;
target.Save();