保护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
}
}
}
有了以上代码不起作用的理解。
您是正确的…如果没有不安全的代码,就无法保存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
}
}