编辑:这种方法可能不适用于处理异常
经过反思,我在下面描述的解决方案可能不适用于捕获和处理异常,至少在没有额外努力的情况下不会。问题是,如果您从语句范围内抛出异常using
,并且您没有在using
语句范围内捕获异常(例如,它在调用堆栈中被进一步捕获),则该using
语句将超出范围在异常被捕获之前。因此,在 using 语句中抛出的异常由异常管理器处理之前,将调用Dispose
in 方法并从堆栈中弹出上下文。ExceptionManagerContext
这是您捕获和记录或以其他方式处理异常的类。您可以向其中添加一个Stack
对象IExceptionManagerContext
,以便您可以Push
和Pop
上下文。
class ExceptionManager
{
private Stack<IExceptionManagerContext> contexts;
public ExceptionManager()
{
contexts = new Stack<IExceptionManagerContext>();
PushContext(new DefaultExceptionManagerContext());
}
public void PushContext(IExceptionManagerContext context)
{
contexts.Push(context);
}
public void PopContext()
{
contexts.Pop();
}
private IExceptionManagerContext CurrentContext
{
get { return contexts.Peek(); }
}
public void Handle(Exception ex)
{
if (CurrentContext.EnableLogging)
{
Log(ex);
}
else
{
DoSomethingElseWith(ex);
}
}
}
堆栈底部的默认上下文可以实现一些默认选项,例如启用日志记录。您可以添加任意数量的其他属性以IExceptionManagerContext
使您的异常管理可配置。
interface IExceptionManagerContext
{
bool EnableLogging { get; }
}
class DefaultExceptionManagerContext : IExceptionManagerContext
{
public bool EnableLogging { get { return true; } }
}
实现了一个自定义上下文类IDisposable
,以便它可以安全地将自己推入/弹出异常管理器中的上下文堆栈。此类将需要对异常管理器的某种引用,或者您的管理器可能是单例等。请注意,这是 IDisposable 的简单实现,它的某些用法可能会导致PopContext
被调用的次数多于PushContext
,因此您可能想要改进实施以确保安全。
class ExceptionManagerContext : IExceptionManagerContext, IDisposable
{
ExceptionManager manager;
public ExceptionManagerContext(ExceptionManager manager)
{
this.manager = manager;
manager.PushContext(this);
}
public bool EnableLogging { get; set; }
public void Dispose()
{
manager.PopContext();
}
}
这是您想要定义一个“上下文”的代码,其中异常处理的行为应该不同。该using
语句将确保设置更改的上下文,然后安全地删除。您可以嵌套这样的 using 语句,递归地运行此代码等,它应该做正确的事情。
using (new ExceptionManagerContext(exceptionManager) { EnableLogging = false })
{
DoSomethingThatMayRaiseExceptions();
}