从内部使用块返回是否可以

我正在进行代码审查,并找到了许多具有以下格式的代码:

public MyResponse MyMethod(string arg) { using (Tracer myTracer = new Tracer(Constants.TraceLog)) { MyResponse abc = new MyResponse(); // Some code return abc; } } 

当我运行代码分析时,我得到一个CA2000警告Microsoft.Reliability

代码应该重写为:

 public MyResponse MyMethod(string arg) { MyResponse abc = new MyResponse(); using (Tracer myTracer = new Tracer(Constants.TraceLog)) { // Some code } return abc; } 

或者没关系?

编辑

报告警告的行是:

 MyResponse abc = new MyResponse(); 

MyResponse是标准的数据集。

完整的错误消息是:

警告150 CA2000:Microsoft.Reliability:在方法’xxxxx(Guid,Guid)’中,对象’MyResponse’未沿所有exception路径放置。 对所有对它的引用超出范围之前,在对象’MyResponse’上调用System.IDisposable.Dispose。

您的重写不会修复CA2000警告,因为问题不是Tracer对象,而是MyResponse对象。
文件说明:

以下是使用语句不足以保护IDisposable对象并可能导致CA2000发生的一些情况。
返回一次性对象需要在使用块之外的try / finally块中构造对象。

要修复警告而不弄乱exception的堆栈跟踪 (< - 单击,这是一个链接),请使用以下代码:

 public MyResponse MyMethod(string arg) { MyResponse tmpResponse = null; MyResponse response = null; try { tmpResponse = new MyResponse(); using (Tracer myTracer = new Tracer(Constants.TraceLog)) { // Some code } response = tmpResponse; tmpResponse = null; } finally { if(tmpResponse != null) tmpResponse .Dispose(); } return response; } 

为什么? 请参阅链接文档中的示例。

不,没关系。

无论您将return放在何处,由using语句隐式生成以处理处理的finally块都将执行。

你确定CA2000与myTracer而不是abc吗? 我猜这个警告正在发生,因为MyResponse实现了IDisposable并且你在返回之前没有处理abc 。 (无论哪种方式,建议的重写都不会对警告产生任何影响。)

警告可能是关于MyResponse ,这是IDisposable

为什么出现警告?

如果构造了一个MyResponse对象,但是稍后在该方法中的代码会导致抛出exception,那么对该对象的所有引用都将丢失(我们只有一个,并且没有设法返回它)。 这意味着不能再在对象上调用Dispose ,我们将依赖类终结器来清理任何资源。

有关系吗?

一般来说,只有在以下情况下才有意义:

  • IDisposable封装了程序的其他部分或其他进程“很快”可能需要的资源
  • 在方法返回之前抛出exception,以触发“问题”
  • 终结器不会很快释放该资源, 或者由于某种原因,终结器永远不会运行,但您的应用程序不会停止运行

所以不,它应该不重要。

怎么解决?

 public MyResponse MyMethod(string arg) { MyResponse abc = null; try { abc = new MyResponse(); using (Tracer myTracer = new Tracer(Constants.TraceLog)) { // Some code return abc; } } catch { if (abc != null) { abc.Dispose(); } throw; } } 

这确保了如果控制通过exception退出方法,则abcnull或已正确处理。

更新

事实certificate,当使用这种处理方式时,将重新抛出MyMethod内部显式抛出的exception,并使第一个堆栈帧的行号突变为指向throw; 声明。

实际上这意味着如果你在MyResponse有多个throw语句,并且它们使用相同的消息抛出相同类型的exception,那么当你捕获exception时,你将无法确定哪个throw是完全负责的。

这是恕我直言,这是一个纯粹的学术问题,但我提到它是完整的。

这并不重要。 但是,与@Aliostad相反,我认为版本2,在using块之外的return是更好的风格。

我的理由是这样的:

using块表示“打开”和“关闭”的内容。 这是一种令人讨厌的交易。 关闭using块说我们已经完成了我们的工作,现在继续使用其他东西是安全的,比如return

这个警告可能与“单一退出点”原则有关。 这里讨论: http : //c2.com/cgi/wiki?SingleFunctionExitPoint