在匿名方法中捕获委托
考虑
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 捕获的操作不会更改 - 只有 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 会以某种方式原生支持它。
谢谢 !
Consider
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();
}
The reason printAction will be called by _captureAction is that the line
action -= printAction;
Actually translates into
action = (Action) Delegate.Remove(action, printAction);
so the action captured by _captureAction in CaptureActionFromParam() is not changed - only the local 'action' variable in TestSimpleCapturedAction() is affected.
My desired behavior in such a scenario would be printAction not being called. The only solution I can think of is defning a new "delegate container" class as such:
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();
}
This works but I wonder if my desired behavior can be achieved without introducing this new layer of abstraction. Implementing the strategy pattern can easily lead to such a situation, so one would reckon the language and/or the BCL would support it natively somehow.
Thanks !
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
代表就像绳子。它们被实现为引用类型,但它们的行为更像不可变值类型。当您在字符串上添加或减去字符时,它不会更改字符串,而是会生成一个新字符串,即新结果。当您对整数进行加法或减法时,它不会改变该整数,而是会产生一个新的整数,即新的结果。当您添加委托或从委托中减去委托时,不会更改任何一个委托;它产生一个新的委托,这就是结果。
如果您要捕获的是一个可以变化的委托,那么捕获一个包含对委托的引用的变量。变量变化,这就是它们被称为“变量”的原因。如果你想要一些可以变化的东西,那就获取变量。
现在,捕获的委托本身捕获了变量“操作”,而不是恰好位于其中的值。
请记住:
有道理吗?
Delegates are like strings. They're implemented as reference types, but they behave more like immutable value types. When you add or subtract characters on a string, it doesn't change the string, it produces a new string that is the new result. When you add or subtract numbers from an integer, it doesn't change the integer, it produces a new integer that is the new result. And when you add or substract a delegate from a delegate, it doesn't change either delegate; it produces a new delegate which is the result.
If what you want to capture is a delegate which can vary then capture a variable that contains a reference to a delegate. Variables vary, that's why they're called "variables". If you want something that can vary, get the variable.
Now the delegate that is captured has itself captured the variable "action", not the value that happens to be in it.
Remember:
Make sense?