C#中的Guard对象

时间:2014-10-16 21:24:45

标签: c# c++

在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
    }
  }
}

了解上述代码无效。

4 个答案:

答案 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块,正如您所说的那样可能会变得混乱。请注意,您只能调用usingIDisposable对象,然后将其处理 - 这是重置相关对象值的完美触发器。