C#是否有办法模拟软件事务内存,小规模?

Joa*_*nge 6 .net c#

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绑定期间抛出,我们希望能够向用户报告!我们不希望错误报告者留下在"压制报告错误"状态.)

  • 有一天,有人应该尝试从你在这里提到的小块和你的博客上对C#编译器进行逆向工程...... (4认同)

Ed *_* S. 12

不,但这样做非常简单:

bool UpdateOnTrue = true;

// ....

bool temp = UpdateOnTrue;
try
{
    UpdateOnTrue = false;
    //  do stuff
}
finally
{
    UpdateOnTrue = temp; 
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*ker 6

尝试:

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)


Jon*_*eet 5

不,你必须使用try/finally块手动完成.我敢说你可以编写一个IDisposable实现,它会与lambda表达式一起做一些hacky,但我怀疑try/finally块更简单(并且不会滥用using语句).