代码之家  ›  专栏  ›  技术社区  ›  Ohad Schneider

以匿名方法捕获委托

  •  4
  • Ohad Schneider  · 技术社区  · 15 年前

    考虑

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

    “CaptureAction调用printAction的原因是

    action -= printAction;
    

    实际上转化为

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

    因此captureActionFromParam()中的captureAction捕获的操作没有更改-只影响testsSimpleCaptureDaction()中的本地“action”变量。

    在这种情况下,我希望的行为是不调用printaction。我能想到的唯一解决方案是将一个新的“委托容器”类定义为:

        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会以某种方式支持它。

    谢谢!

    1 回复  |  直到 13 年前
        1
  •  7
  •   Eric Lippert    15 年前

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

    如果要捕获的是一个可以 变化 然后 捕获包含对委托的引用的变量 .变量 变化 这就是它们被称为“变量”的原因。如果你想要一些可以改变的东西,得到这个变量。

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

    现在,捕获的委托本身已捕获 变量 “行动”,而不是 价值 就在里面。

    记得:

    • 参数已传递 按价值 .
    • 拉姆达斯捕捉 变量 不是 价值观 .

    有道理?