在我正在进行攻击的API实现中,需要在执行某项任务之前暂时重复更改某些变量,并在完成任务之后将其更改回原来的任何变量。
目前的代码如下:
var _oldValue = _variable;
_variable = tempValue;
try
{
doIt();
}
finally
{
_variable = oldValue;
}
这么做很烦人,很难看,很难维护,并且在很多杂乱的情况下掩盖了实际的算法,这只是实现工件。
在C ++中,我会创建一个在构造期间在某处存储旧值的类,并在其析构函数中恢复它:
{
temp_value tmp(variable_, temp_val);
do_it();
}
尝试在C#I failed中尝试类似的事情,因为显然是C# can't store references to other objects in classes。
那么在C#中我需要做些什么才能消除这种混乱?
P.S。:随意添加您认为合适的任何其他标签。我没有提出任何问题。
答案 0 :(得分:7)
虽然我同意Eric Lippert的理想解决方案,但有些情况下,被迫临时改变可变的状态并执行某些操作。即在SharePoint对象模型中有几个这样的需求示例,因此无法重新设计代码以避免它。
下面是可用于临时修改值并使用using
语句进行恢复的代码。使用using
用于此类非释放 - 非管理资源的目的是争用,因此请判断此类方法是否适用于您:
使用示例:
using(TemporaryChange(true, myValue, v => myValue = v))
{
// code to run while "myValue" is changed to "true"
}
类别:
class TemporaryChange<V> : IDisposable
{
private V original;
private Action<V> setValue;
internal TemporaryChange(V value, V currentValue, Action<V> setValue)
{
this.setValue = setValue;
this.original = currentValue;
this.setValue(value);
}
void IDisposable.Dispose()
{
this.setValue(this.original);
}
}
答案 1 :(得分:6)
为什么不创建一个为您执行此操作的方法,然后将Lamda传递给它?
private void SaveGlobalsAndDoSomething(Action doit)
{
var _oldValue = _variable;
_variable = tempValue;
try
{
doit();
}
finally
{
_variable = _oldValue;
}
}
使用它:
SaveGlobalsAndDoSomething(() => { DoSomething(); });
编辑以回应评论:
doit
有时返回一个值不是问题。我们没有将DoSomething
传递给该方法。我们将{ DoSomething(); }
传递给该方法。所以你可以轻松地写下:
int returnValue;
SaveGlobalsAndDoSomething(() => { returnValue = DoSomething(); });
答案 2 :(得分:6)
事实上,你正在考虑做一些可怕的,可怕的事情来解决这个问题,这表明你不应该首先处于这种情况。如果您处于代码依赖于变异然后取消突变状态的情况,那么您的设计就会很糟糕。 修复真正的设计问题,而不是试图想出一种聪明的方法来继续使用糟糕的架构。
当我处于这种情况时,我所做的就是克隆我的状态。假设你这样做:
class Frobber
{
State state;
...
void M()
{
...
try
{
oldstate = state;
state = newstate;
this.DoIt();
}
finally
{
state = oldstate;
}
}
而是这样做:
class Frobber
{
State state;
...
void M()
{
...
Frobber newFrobber = new Frobber(newstate);
newFrobber.DoIt();
...
不是改变变量并改变它,而是创建一个全新的变量。完成后,丢弃新变量。旧变量不需要变回,因为它永远不会改变。