C#是否有办法暂时更改特定范围内变量的值,并在范围/块的末尾自动将其还原?
例如(不是真正的代码):
bool UpdateOnInput = true;
using (UpdateOnInput = false)
{
//Doing my changes without notifying anyone
Console.WriteLine (UpdateOnInput) // prints false
}
//UpdateOnInput is true again.
Run Code Online (Sandbox Code Playgroud)
编辑:
我想要上述的原因是因为我不想这样做:
UpdateOnInput = false
//Doing my changes without notifying anyone
Console.WriteLine (UpdateOnInput) // prints false
UpdateOnInput = true
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 13
不,没有办法直接这样做.关于如何做这种事情有几种不同的思想流派.比较和对比这两个:
originalState = GetState();
SetState(newState);
DoSomething();
SetState(originalState);
Run Code Online (Sandbox Code Playgroud)
VS
originalState = GetState();
SetState(newState);
try
{
DoSomething();
}
finally
{
SetState(originalState);
}
Run Code Online (Sandbox Code Playgroud)
很多人会告诉你,后者更"安全".
不一定如此.
两者之间的区别当然是后者即使DoSomething()抛出异常也会恢复状态.这比在异常情况下保持状态变异更好吗? 是什么让它变得更好? 您有一个意外的,未处理的异常,报告发生了可怕和意外的事情.你的内部状态可能完全不一致,任意搞砸了; 没人知道异常时可能发生了什么.我们所知道的是DoSomething可能正试图对变异状态做些什么.
难道真的在什么可怕的未知发生了继续搅拌特定的锅,并试图变异,只是导致了异常状态的情况下做正确的事情再次?
有时这将是正确的事情,有时它会使事情变得更糟.你实际上处于哪种情况取决于代码究竟在做什么,所以在盲目地选择其中一个之前,要仔细考虑正确的事情.
坦率地说,我宁愿通过不首先进入这种情况来解决问题.我们现有的编译器设计使用了这种设计模式,坦率地说,它令人生气.在现有的C#编译器中,错误报告机制是"副作用".也就是说,当编译器的一部分收到错误时,它会调用错误报告机制,然后向用户显示错误.
这是lambda绑定的主要问题.如果你有:
void M(Func<int, int> f) {}
void M(Func<string, int> f) {}
...
M(x=>x.Length);
Run Code Online (Sandbox Code Playgroud)
然后它的工作方式是我们试图绑定
M((int x)=>{return x.Length;});
Run Code Online (Sandbox Code Playgroud)
和
M((string x)=>{return x.Length;});
Run Code Online (Sandbox Code Playgroud)
我们看到哪一个,如果有的话,给我们一个错误.在这种情况下,前者给出错误,后者编译没有错误,因此这是合法的lambda转换和重载解析成功.我们如何处理错误? 我们无法向用户报告,因为该程序没有错误!
因此,当我们绑定lambda的主体时我们所做的正是你所说的:我们告诉错误记者"不要向用户报告你的错误;而是将它们保存在这个缓冲区中".然后我们绑定lambda,将错误报告器恢复到其早期状态,并查看错误缓冲区的内容.
我们可以通过更改表达式分析器来完全避免这个问题,以便它返回错误和结果,而不是使错误成为与状态相关的副作用.然后,错误报告状态的变异需求完全消失,我们甚至不必担心它.
所以我鼓励你重新审视你的设计.有没有办法可以让你执行的操作不依赖于你正在改变的状态?如果是这样,那么这样做,然后你不必担心如何恢复变异状态.
(当然在我们的情况下,我们确实希望在异常时恢复状态.如果编译器内部的某些东西在lambda绑定期间抛出,我们希望能够向用户报告!我们不希望错误报告者留下在"压制报告错误"状态.)
Ed *_* S. 12
不,但这样做非常简单:
bool UpdateOnTrue = true;
// ....
bool temp = UpdateOnTrue;
try
{
UpdateOnTrue = false;
// do stuff
}
finally
{
UpdateOnTrue = temp;
}
Run Code Online (Sandbox Code Playgroud)
尝试:
public void WithAssignment<T>(ref T var, T val, Action action)
{
T original = var;
var = val;
try
{
action();
}
finally
{
var = original;
}
}
Run Code Online (Sandbox Code Playgroud)
现在你可以说:
bool flag = false;
WithAssignment(ref flag, true, () =>
{
// flag is true during this block
});
// flag is false again
Run Code Online (Sandbox Code Playgroud)