范围可以用“using”来阻止吗?关键字对异常有反应吗?
我需要在我的代码中进行一些日志记录。我需要使用公司内部开发的库来记录一些信息。这是它的工作原理。
Recorder recorder = Recorder.StartTiming();
DoSomeWork();
recorder.Stop(); // Writes some diagnostic information.
为了确保 Stop() 始终被调用,我创建了一个包装类,它允许干净的“using”块。
using (RecorderWrapper recorderWrapper = new RecorderWrapper) // Automatically calls Recorder.StartTiming() under the covers
{
DoSomeWork();
} // When the recorderWrapper goes out of scope, the 'using' statement calls recorderWrapper.Dispose() automatically - which calls recorder.Stop() under the covers
到目前为止效果很好。但是,我的公司需要进行一项更改,原始代码看起来像这样:
Recorder recorder = Recorder.StartTiming();
try
{
DoSomeWork();
}
catch (Exception ex)
{
recorder.ReportFailure(ex); // Write out some exception details associated with this "transaction"
}
recorder.Stop(); // Writes some diagnostic information.
我想避免在使用 RecorderWrapper 的所有“使用”范围块中进行 try/catch。有没有办法可以容纳“ReportFailure()”调用并仍然利用“using”范围块?
具体来说,我希望团队中的每个人都能“陷入成功的深渊”,即轻松地做正确的事情。对我来说,这意味着很难忘记调用 recorder.Stop() 或忘记 try/catch。
谢谢!
I have the need to do some logging within my code. I'm required to use an internal company-developed library to record some information. Here's how it works.
Recorder recorder = Recorder.StartTiming();
DoSomeWork();
recorder.Stop(); // Writes some diagnostic information.
To ensure that Stop() is always called, I created a wrapper class that allows a clean "using" block.
using (RecorderWrapper recorderWrapper = new RecorderWrapper) // Automatically calls Recorder.StartTiming() under the covers
{
DoSomeWork();
} // When the recorderWrapper goes out of scope, the 'using' statement calls recorderWrapper.Dispose() automatically - which calls recorder.Stop() under the covers
it's worked well so far. However, there's a change my company is requiring, that would look something like this on the original code:
Recorder recorder = Recorder.StartTiming();
try
{
DoSomeWork();
}
catch (Exception ex)
{
recorder.ReportFailure(ex); // Write out some exception details associated with this "transaction"
}
recorder.Stop(); // Writes some diagnostic information.
I'd like to avoid try/catches in all my 'using' scope blocks with RecorderWrapper. Is there a way I can accomodate the "ReportFailure()" call and still leverage the 'using' scope block?
Specifically, I want everyone on my team to "fall into a pit of success", i.e. make it easy to do the right thing. To me, this means making it really hard to forget to call recorder.Stop() or forget the try/catch.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
您也许可以在记录器上创建一个方法来隐藏它:
所以您的示例将是:
You might be able to create a method on the recorder to hide this:
So your example would then just be:
您总是可以尝试类似的方法:
280Z28 编辑:我在这里使用类似于
Stopwatch.StartNew()
。将您的Recorder
类设置为IDisposable
,并从Dispose()
调用Stop()
。我认为没有比这更清楚的了。You could always try something like:
Edit by 280Z28: I'm using a static
StartNew()
method here similar toStopwatch.StartNew()
. Make yourRecorder
classIDisposable
, and callStop()
fromDispose()
. I don't think it gets any more clear than this.您可以继续使用现有的 RecorderWrapper,但添加一个 TryExecuting 方法,该方法接受您想要发生的情况的 lambda,并在 try/catch 块中运行它。例如:
RecorderWrapper 内部:
You could continue to use the RecorderWrapper you have, but add a TryExecuting method that accepts a lambda of what you want to happen add runs it in a try/catch block. eg:
Inside RecorderWrapper:
您可以复制
TransactionScope
使用的模式,并编写一个必须主动完成的包装器 - 如果您不调用Complete()
,然后Dispose()
方法(无论哪种方式都会被调用)假设一个异常并执行您的处理代码:不过,就我个人而言,我会坚持使用 try/catch - 这对将来的维护者来说更清楚- 并且它提供对
异常
的访问。You could copy the pattern used by
TransactionScope
, and write a wrapper that must be actively completed - if you don't callComplete()
, then theDispose()
method (which gets called either way) assumes an exception and does your handling code:Personally, though, I'd stick with try/catch - it is clearer for maintainers in the future - and it provides access to the
Exception
.不,using 块只是 try/finally 块的语法糖。它不涉及 try/catch。那时您将不得不自己处理它,因为看起来您需要例外来进行日志记录。
No, a using block is only syntactic sugar for a try/finally block. It doesn't deal with try/catch. At that point you're going to be left with handling it yourself since it looks like you need the exception for logging purposes.
using 块实际上是一个 try/finally 块,它对相关对象调用 dispose。
所以,这:(
我认为,完全)等同于:
并且您可以将捕获物附加到 try 块的末尾。
编辑:
作为罗布解决方案的替代方案:
A using block is effectively a try/finally block that calls dispose on the object in question.
So, this:
is (i think, exactly) equivalent to this:
And you can tack your catches onto the end of the try block.
Edit:
As an alternative to Rob's solution:
糟糕,我没有注意到 StartTiming 正在创建一个新的 Recorder 实例。我已经更新了代码来解决这个问题。 Wrap 函数现在不再采用 Recorder 参数,而是将它创建的记录器作为参数传递给调用者传入的操作委托,以便调用者可以在需要时使用它。
嗯,我已经需要做一些与此模式非常相似的事情,lambda、Action 委托和闭包使这一切变得容易:
首先定义一个类来进行包装:
现在,像这样使用:
但有一个问题 - 是否真的希望 catch 处理程序吞下异常而不重新抛出它?这通常是一个不好的做法。
顺便说一句,我将对此模式添加一个有用的补充。虽然,听起来它并不适用于您在这种情况下所做的事情:曾经想做类似上面的事情,您想要用一组启动操作和完成操作来包装一些代码,但您也需要能够编写一些特定的异常处理代码。好吧,如果您将 Wrap 函数更改为也采用 Action 委托并将 T 约束为 Exception,那么您就得到了一个包装器,它允许用户指定要捕获的异常类型以及要执行的代码来处理它,例如
: use..(请注意,您必须指定异常的类型,因为它显然无法推断出来。这就是您想要的):
然后,您可以通过提供 Wrap 函数的多个重载来扩展此模式,该重载接受多个异常处理程序委托。通常五个重载就足够了 - 您需要一次捕获五种以上不同类型的异常是很不寻常的。
Oops, I hadn't noticed that a new instance of Recorder was being created by StartTiming. I've updated the code to account for this. The Wrap function now no longer takes a Recorder parameter but instead passes the recorder it creates as an argument to the action delegate passed in by the caller so that the caller can make use of it if needed.
Hmmm, I've needed to do something very similar to this pattern, lambdas, the Action delegate and closures make it easy:
First define a class to do the wrapping:
Now, use like so:
One question though - is it really desired that the catch handler swallows the exception without rethrowing it? This would usually be a bad practice.
BTW, I'll throw in an addition to this pattern which can be useful. Although, it doesn't sound like it applies to what you're doing in this instance: Ever wanted to do something like the above where you want to wrap some code with a set of startup actions and completion actions but you also need to be able to code some specific exception handling code. Well, if you change the Wrap function to also take an Action delegate and constrain T to Exception, then you've got a wrapper which allows user to specify the exception type to catch, and the code to execute to handle it, e.g.:
To use.. (Note you have to specify the type of exception, as it obviously cannot be inferred. Which is what you want):
You can then extend this pattern by providing multiple overloads of the Wrap function which take more than one exception handler delegate. Usually five overloads will be sufficient - it's pretty unusual for you to need to catch more than five different types of exceptions at once.
不要添加另一级间接。如果需要捕获异常,请使用
try..catch..finally
并在finally
块中调用Dispose()
。Don't add another level of indirection. If you need to catch the Exception, use
try..catch..finally
and callDispose()
in thefinally
block.