Как глубоко скопировать объект, содержащий лямбда-выражение? - PullRequest
0 голосов
/ 07 января 2010

Это снова я о моей игре Mega Man. Я переключился на систему компонентов, чтобы объекты могли управлять данными. Все идет хорошо, но я столкнулся с проблемой.

Мои объекты имеют состояния, указанные во входном файле. Эти штаты имеют триггеры для перехода их в другие штаты. Условия для изменения состояния также находятся во входном файле и анализируются в лямбда-выражении. Теперь мне нужно глубоко скопировать мои объекты, и мне нужны лямбды, чтобы ссылаться на элементы копии, а не на элементы оригинала. Оригиналы загружаются из файла при загрузке программы, но могут быть скопированы в любое время после этого (например, снаряды запускаются).

Вот очень упрощенный фрагмент кода:

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

Это нечто большее, триггеры фактически вызывают изменение состояния, а затем инициализатор нового состояния вызывает это действие, но я упростил его здесь.

Так что проблема в том, что когда я копирую этот компонент или пытаюсь в любом случае, я не знаю, как сделать так, чтобы лямбды ссылались на экземпляр копии DependentComponent, а не на оригинал. Я уже убедился, что глубокая копия сущности получает новый DependentComponent, но лямбда просто ссылается на оригинал. Является ли делегат в основном привязанным к конкретным экземплярам после создания? Должен ли я создать новый? Я не хочу снова загружать всю сущность из файла.

Ответы [ 2 ]

0 голосов
/ 07 января 2010

Деревья выражений неизменны, поэтому, если в них есть ссылки на объекты, они будут исходными объектами. Чтобы глубоко скопировать его, вам понадобится какой-нибудь посетитель с заменой; У меня где-то есть похожий код, но это много работы. Конечно, если не содержит ссылки на объект, вы можете просто использовать его «как есть» довольно безопасно.

Предполагая, что вы имеете в виду поле LambdaExpression lambda; Я не знаком с тем, как вы его анализируете, поэтому я не могу комментировать, как легко это было бы сделать, но распространенный вариант здесь - параметризация лямбда-выражения; передать целевой объект в качестве аргумента, и вы можете повторно использовать лямбду с несколькими различными объектами во время выполнения (при условии, что они имеют соответствующий тип).

0 голосов
/ 07 января 2010

Почему бы не сделать это аргументом лямбды?

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

Если вам требуется более одного зависимого компонента, вы также можете передать указатель this, если вы хотите поменять лямбда-выражения между объектами разных классов, используйте интерфейс ...

...