代码之家  ›  专栏  ›  技术社区  ›  Tesserex

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

  •  0
  • Tesserex  · 技术社区  · 15 年前

    又是我,关于我的超级男人游戏。我切换到一个组件系统,以便对象可以由数据驱动。一切正常,但我遇到了一个问题。

    我的对象有状态,由输入文件指定。这些状态具有将它们转换为其他状态的触发器。状态更改的条件也在输入文件中,并被解析为lambda表达式。现在我需要深度复制我的对象,我需要lambda指的是副本的成员,而不是原始的成员。当程序加载时,原始文件从文件中加载,但可以在加载后的任何时间复制(考虑发射物)。

    下面是一个大大简化的代码:

    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;
        }
    }
    

    除此之外,触发器实际上会导致状态更改,然后新状态的初始值设定项调用该操作,但我在这里简化了它。

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

    2 回复  |  直到 15 年前
        1
  •  0
  •   Stefan Steinegger    15 年前

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

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

    如果您需要一个以上的依赖组件,也可以传递这个指针,如果您想在不同类的对象之间交换lambda,请使用一个接口…

        2
  •  0
  •   Marc Gravell    15 年前

    表达式树是不可变的,因此如果其中包含对象引用,则它们将指向原始对象。要深入复制它,您需要某种具有替换功能的访问者;我在某个地方有一些类似的代码,但这是一项很大的工作。当然,如果它 在其中包含特定于对象的引用,您可以非常安全地“按原样”使用它。

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