2010-02-20 22 views
4

考虑在匿名方法捕获代表

Action _captureAction; 
    private void TestSimpleCapturedAction() 
    { 
     Action action = new Action(delegate { }); 
     Action printAction =() => Console.WriteLine("Printing..."); 

     action += printAction; 
     CaptureActionFromParam(action); 
     action -= printAction; 

     _captureAction(); //printAction will be called! 
    } 

    private void CaptureActionFromParam(Action action) 
    { 
     _captureAction =() => action(); 
    } 

原因printAction将_captureAction被称为是该行

action -= printAction; 

其实翻译成

action = (Action) Delegate.Remove(action, printAction); 

这样的动作被抓获CaptureActionFromParam()中的_captureAction不会更改 - 只有TestSimp中的本地'action'变量leCapturedAction()受到影响。

在这种情况下,我希望的行为是printAction不被调用。我能想到的唯一的办法就是defning一个新的“委托容器”级这样:

class ActionContainer 
    { 
     public Action Action = new Action(delegate { }); 
    } 

    private void TestCapturedActionContainer() 
    { 
     var actionContainer = new ActionContainer(); 
     Action printAction =() => Console.WriteLine("Printing..."); 

     actionContainer.Action += printAction; 
     CaptureInvoker(actionContainer); 
     actionContainer.Action -= printAction; 

     _captureAction(); 
    } 

    private void CaptureInvoker(ActionContainer actionContainer) 
    { 
     _captureAction =() => actionContainer.Action(); 
    } 

这工作,但我不知道是否可以在不引入抽象的这个新层来实现我所期望的行为。实施战略模式很容易导致这种情况,所以人们会认为这种语言和/或BCL会以某种方式在本地支持它。

谢谢!

回答

7

代表就像字符串。它们被实现为引用类型,但它们更像不可变的值类型。当您添加或减去字符串上的字符时,它不会更改字符串,它会生成一个新的字符串,即新的结果。当你从一个整数中加或减数字时,它不会改变整数,它会产生一个新的整数,它是新的结果。并且,当您从委托中添加或减去委托时,它不会更改任何委托;它产生了一个新的代表,这是结果。

如果你想捕捉的是一个代表可变化然后捕获包含对委托引用的变量。变量各不相同,这就是为什么他们被称为“变量”。如果你想要的东西可以变化,获取变量。

CaptureActionFromParam(()=>{action();}); 

现在被捕获委托具有自身拍摄的变量“行动”,而不是恰好是在里面。

记住:

  • 参数是按值传递
  • 兰姆达斯捕获变量,而不是

有意义吗?

+0

哇,这个人自己答案!我实际上意识到你的观点,这就是为什么我提出上面的“可变动作”类解决方案(MutalbeAction比ActionContainer更好的名称),但CaptureActionFromParam((=)action>)更加优雅。谢谢 ! – 2010-02-20 18:43:54