在C ++中,编写一个引用变量(通常是bool)的Guard类非常容易,当实例对象退出作用域并被破坏时,析构函数会将变量重置为原始值。
void someFunction() {
if(!reentryGuard) {
BoolGuard(&reentryGuardA, true);
// do some stuff that might cause reentry of this function
// this section is both early-exit and exception proof, with regards to restoring
// the guard variable to its original state
}
}
我正在寻找一种优雅的方式在C#中使用处理模式(或者其他一些机制)来实现这一点?我认为将委托传递给调用可能会有效,但似乎比错误更容易出错上面的守卫。建议欢迎!
类似的东西:
void someFunction() {
if(!reentryGuard) {
using(var guard = new BoolGuard(ref reentryGuard, true)) {
// do some stuff that might cause reentry of this function
// this section is both early-exit and exception proof, with regards to restoring
// the guard variable to its original state
}
}
}
了解上述代码无效。
答案 0 :(得分:2)
你是对的...没有不安全的代码,你不能保存by-ref参数的地址。但是,根据您可以改变整体设计的程度,您可以创建一个可保护的"类型,这样它就是一个包含实际保护值的引用类型。
例如:
class Program
{
class Guardable<T>
{
public T Value { get; private set; }
private sealed class GuardHolder<TGuardable> : IDisposable where TGuardable : Guardable<T>
{
private readonly TGuardable _guardable;
private readonly T _originalValue;
public GuardHolder(TGuardable guardable)
{
_guardable = guardable;
_originalValue = guardable.Value;
}
public void Dispose()
{
_guardable.Value = _originalValue;
}
}
public Guardable(T value)
{
Value = value;
}
public IDisposable Guard(T newValue)
{
GuardHolder<Guardable<T>> guard = new GuardHolder<Guardable<T>>(this);
Value = newValue;
return guard;
}
}
static void Main(string[] args)
{
Guardable<int> guardable = new Guardable<int>(5);
using (var guard = guardable.Guard(10))
{
Console.WriteLine(guardable.Value);
}
Console.WriteLine(guardable.Value);
}
}
答案 1 :(得分:2)
这是一种功能性(如基于lambda的方式)。优点是,无需使用:
(注意:这不是线程安全的。如果您希望让不同的线程同时运行相同的代码,请查看锁定语句,监视器和互斥锁)
// usage
GuardedOperation TheGuard = new GuardedOperation() // instance variable
public void SomeOperationToGuard()
{
this.TheGuard.Execute(() => TheCodeToExecuteGuarded);
}
// implementation
public class GuardedOperation
{
public bool Signalled { get; private set; }
public bool Execute(Action guardedAction)
{
if (this.Signalled)
return false;
this.Signalled = true;
try
{
guardedAction();
}
finally
{
this.Signalled = false;
}
return true;
}
}
修改强>
以下是如何使用带参数的守卫:
public void SomeOperationToGuard(int aParam, SomeType anotherParam)
{
// you can pass the params to the work method using closure
this.TheGuard.Execute(() => TheMethodThatDoesTheWork(aParam, anotherParam);
}
private void TheMethodThatDoesTheWork(int aParam, SomeType anotherParam) {}
您还可以引入Execute方法的重载,该方法接受Action委托的几个不同变体,例如Action&lt; T&gt;和行动&lt; T1,T2&gt;
如果需要返回值,可以引入接受Func&lt; T&gt;
的Execute重载答案 2 :(得分:0)
您可以从IDisposable界面派生您的对象并实现它。
在您提交的具体案例中,只要您离开Dispose
范围,就会调用 using
。
示例:
public class BoolGuard : IDisposable
{
....
...
public void Dispose()
{
//DISPOSE IMPLEMANTATION
}
}
答案 3 :(得分:0)
听起来你必须自己实现的东西 - 虽然我在MSDN上找到了deprecated class Guard,但在C#或.NET框架中没有这样的机制。
这种功能可能需要使用Using
语句来操作而不会传递Action
块,正如您所说的那样可能会变得混乱。请注意,您只能调用using
和IDisposable
对象,然后将其处理 - 这是重置相关对象值的完美触发器。