保护C#中的对象

本文关键字:对象 保护 | 更新日期: 2023-09-27 18:26:53

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

有了以上代码不起作用的理解。

保护C#中的对象

您是正确的…如果没有不安全的代码,就无法保存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);
    }
}

这里有一种函数式(如基于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<T>以及Action<T1、T2>

如果需要返回值,可以引入接受Func<T>

听起来像是你必须自己实现的事情——C#或.NET框架中没有内置这样的机制,尽管我确实在MSDN上找到了一个不推荐使用的类Guard。

这类功能可能需要使用Using语句来操作,而不需要传递Action块,正如您所说,这可能会变得混乱。请注意,您只能针对和IDisposable对象调用using,然后将对其进行处理——这是重置有问题对象值的完美触发器。

您可以从IDisposable接口派生对象并实现它。

在您在此演示的特定情况下一旦您离开using范围,就会调用Dispose

示例:

public class BoolGuard : IDisposable 
{
       .... 
       ...      
        public void Dispose()
        { 
            //DISPOSE IMPLEMANTATION
        }
}