以匿名方法捕获代表

时间:2010-02-20 18:09:10

标签: c# delegates strategy-pattern

考虑

    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捕获的操作不会更改 - 只会影响TestSimpleCapturedAction()中的本地“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 个答案:

答案 0 :(得分:7)

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

如果您想要捕获的是一个可以变化的委托,那么捕获一个包含对委托的引用的变量。变量变化,这就是为什么它们被称为“变量”。如果你想要变化的东西,可以得到变量。

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

现在,捕获的委托本身捕获了变量“action”,而不是恰好位于其中的

记住:

  • 参数按值传递
  • Lambdas捕获变量,而非

有意义吗?