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

_captureAction 将调用 printAction 的原因是该行

action -= printAction;

实际上翻译成

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

因此 CaptureActionFromParam() 中 _captureAction 捕获的动作不会改变 - 只有 TestSimpleCapturedAction() 中的本地“动作”变量受到影响。

在这种情况下,我想要的行为是不调用 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 会以某种方式原生支持它。

谢谢 !

4

1 回答 1

7

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

如果您要捕获的是可以变化的委托,则捕获包含对委托的引用的变量。变量有所不同,这就是为什么它们被称为“变量”。如果您想要可以变化的东西,请获取变量。

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

现在被捕获的委托本身已经捕获了变量“action”,而不是恰好在其中的值。

记住:

  • 参数按值传递。
  • Lambdas 捕获变量,而不是

有道理?

于 2010-02-20T18:31:40.963 回答