如何深度复制包含lambda表达式的对象?

时间:2010-01-07 20:40:19

标签: c# lambda deep-copy

关于我的Mega Man游戏,这又是我。我切换到组件系统,以便对象可以被数据驱动。它没问题,但我遇到了问题。

我的对象具有使用输入文件指定的状态。这些州有触发器将其转移到其他州。状态更改的条件也在输入文件中,并被解析为lambda表达式。现在我需要深度复制我的对象,我需要lambdas来引用副本的成员而不是原始成员。程序加载时会从文件中加载原件,但可以在之后的任何时间复制(认为射弹被射击)。

这是一段非常简化的代码:

class StateComponent
{
    // when the whole entity is cloned, it will get a clone of
    // DependentComponent as well as a clone of this StateComponent.
    private OtherComponent DependentComponent;

    // there is a function to register dependencies. The entity that owns
    // me also owns DependentComponent, and registered it with me.

    public StateComponent Clone()
    {
        // what should I do here to make the lambda deep copied?
    }

    public void LoadFromXml(XElement node)
    {
        State state = new State();
        LambdaExpression lambda = DynamicExpression.ParseLambda(from xml stuff)
        Delegate condition = lambda.Compile();
        Action effect = LoadTriggerEffect();
        state.AddTrigger(condition, effect);

        // add state to my list of states
    }

    private Action LoadTriggerEffect()
    {
        Action action = new Action(() => { });
        if ( some stuff from the input file )
            action += () => { DependentComponent.Foo(); DependentComponent.Bar = 5; }

        return action;
    }
}

除此之外,触发器实际上会导致状态更改,然后新状态的初始化程序会调用该Action,但我在此处对其进行了简化。

所以问题是,当我深度复制这个组件,或者尝试无论如何,我不知道如何使它成为lambda引用副本的DependentComponent实例,而不是原始的实例。我已经确定实体的深层副本正在获取一个新的DependentComponent,但lambda只是引用原始的。委托是否在创建后基本上锁定到特定实例?我需要创建一个新的吗?我不想再次从文件中加载整个实体。

2 个答案:

答案 0 :(得分:0)

为什么不把它作为lambda的参数?

Action<OtherComponent> action = new Action<OtherComponent>((null) => { });
if ( some stuff from the input file )
    action += x => { x.Foo(); x.Bar = 5; }

如果你需要更多只有一个依赖组件,你也可以传递this指针,如果你想在不同类的对象之间交换lambda,使用一个接口...

答案 1 :(得分:0)

表达式树是不可变的,因此如果它具有对象引用,它们将是原始对象。要深层复制它,你需要一些替代的访客;我在某处有类似的代码,但这是很多工作。当然,如果 中没有具有特定于对象的引用,您可以非常安全地“按原样”使用它。

假设你的意思是LambdaExpression lambda字段;我不熟悉你是如何解析它的,所以我不能评论它是多么容易,但这里常见的选择是参数化lambda;将目标对象作为参数传递,并且可以在运行时将lambda与多个不同的对象一起使用(只要它们具有适当的类型)。