我一直在探索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,无参数的委托,它在另一个对象里面仍然可以工作?这里发生了什么?创建匿名函数是否引用它包含的所有对象?
与将命名函数分配给具有匹配的返回/参数类型的委托相比,这似乎非常灵活,但是有任何主要的缺点或缺陷吗?此外,这种技术是否与任何特定设计模式或编程方法相关(或部分)?
答案 0 :(得分:1)
如果我理解正确,这是有效的,因为匿名函数使用closures。闭包是代码块,可以capture (See: Variable Scope In Lambda Expressions)它们所在的变量环境。
因此,因为CreateCustomCommand方法定义了一个匿名函数(一个闭包),所以匿名函数捕获并维护了对CreateCustomCommand范围内的变量的访问。
感谢@HansPassant指出我正确的方向!