传递匿名/ lambda函数以使没有参数的委托无效? [C#]

时间:2014-09-25 08:55:25

标签: c# lambda delegates anonymous-function

我一直在探索C#代理和匿名/ lambda函数,我对它们如何交互有一些疑问。根据我的理解,一个简单的委托对象可以有预定义的返回和参数类型,任何具有相同返回/参数类型的命名函数都可以分配给委托。

然而,在我的情况下,我一直在开发一个游戏,玩家可以将多个命令排入其命令列表中。在添加到命令列表后的某个时刻,命令最终由播放器执行..

我开始通过为每个命令创建特定的子类(AttackCommand,HealCommand等)来实现这一点,但后来发现,当涉及到各种新命令的原型设计时乏味。。我认为,为了测试目的,使用成员委托创建一个CustomCommand类是很酷的,这样我就可以匿名定义和传递函数,并快速迭代新的游戏设计思想。

public class CustomCommand : Command {

    public delegate void CommandDelegate();
    private CommandDelegate func;

    public CustomCommand( CommandDelegate del ){
        func = del;
    }

    public Execute(){
        func();
    }
}

然后,Player有一个定义匿名函数的方法,并使用它来构造一个CustomCommand。但是,让我感到困惑的一点是,这个方法的参数似乎能够存储在CustomCommand的委托中:

//inside Player class..
//command to steal gold from a target!
public CreateCustomCommand( Player targetPlayer ){
    CustomCommand.CommandDelegate anonCommand = delegate()
    {
         //Steals up to amount passed..
         int goldToSteal = targetPlayer.StealGold(25);
         gold += goldToSteal;
    };

    CustomCommand newCommand = new CustomCommand( anonCommand );
    commandList.Enqueue( newCommand );
}

//Command is automatically executed later..

我已尝试过这段代码,不仅可以编译,还可以使用;钱从目标中被盗并添加到源播放器中。我很高兴它有效,但我有点不安,因为我不确定幕后到底发生了什么......

以下是我很难理解的内容:

在CreateCustomCommand方法(播放器)中, gold在范围内,因为它是Player类的成员, targetPlayer在范围内,因为它是一个参数 ..但是这些东西怎么能被包含在一个匿名函数中并传递给一个void,无参数的委托,它在另一个对象里面仍然可以工作?这里发生了什么?创建匿名函数是否引用它包含的所有对象?

与将命名函数分配给具有匹配的返回/参数类型的委托相比,这似乎非常灵活,但是有任何主要的缺点或缺陷吗?此外,这种技术是否与任何特定设计模式或编程方法相关(或部分)?

1 个答案:

答案 0 :(得分:1)

如果我理解正确,这是有效的,因为匿名函数使用closures。闭包是代码块,可以capture (See: Variable Scope In Lambda Expressions)它们所在的变量环境。

因此,因为CreateCustomCommand方法定义了一个匿名函数(一个闭包),所以匿名函数捕获并维护了对CreateCustomCommand范围内的变量的访问。

感谢@HansPassant指出我正确的方向!