我正在进行代码审查,并找到了大量具有以下格式的代码:
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'未沿所有异常路径放置。在对所有引用超出范围之前,调用System.IDisposable.Dispose对象'MyResponse'。
答案 0 :(得分:15)
不,没关系。
无论您放置finally
的位置,using
语句隐式生成的用于处理处理的return
块都将执行。
您确定CA2000与myTracer
而非abc
相关吗?我猜这个警告正在发生,因为MyResponse
实现了IDisposable
并且您在返回之前没有处置abc
。 (无论哪种方式,建议的重写都不会对警告产生任何影响。)
答案 1 :(得分:11)
您的重写不会修复CA2000警告,因为问题不是Tracer
对象,而是MyResponse
对象。
The documentation州:
以下是使用声明不足以保护IDisposable对象并可能导致CA2000发生的一些情况。
返回一次性对象需要在使用块之外的try / finally块中构造对象。
要修复警告without messing with the stack trace of your exceptions(< - click,这是一个链接),请使用以下代码:
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;
}
为什么呢?请参阅链接文档中的示例。
答案 2 :(得分:4)
警告可能约为MyResponse
,即IDisposable
。
如果构造了MyResponse
对象,但该方法稍后的代码会导致抛出异常,那么对该对象的所有引用都将丢失(我们只有一个,并且没有设法返回它)。这意味着无法再在对象上调用Dispose
,我们将依赖类终结器来清理任何资源。
一般来说,只有在以下情况下才会有用:
IDisposable
封装了程序其他部分或其他流程“很快”可能需要的资源所以不,它应该不重要。
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;
}
}
这可确保如果控制通过例外退出方法,则abc
可以是null
,也可以正确处理。
事实证明,当使用这种处理方式时,将重新抛出从MyMethod
内部显式抛出的异常,并使第一个堆栈帧的行号突变为指向throw;
声明。
实际上,这意味着如果throw
内有多个MyResponse
语句,并且它们使用相同的消息抛出相同类型的异常,您将无法分辨哪个throw
当你发现异常时,它正是负责任的。
这是恕我直言,这是一个纯粹的学术问题,但我提到它是完整的。
答案 3 :(得分:2)
这并不重要。但是,与@Aliostad相反,我认为版本2,return
块之外的using
是更好的风格。
我的理由是这样的:
using
块表示“打开”和“关闭”的内容。这是一种令人讨厌的交易。关闭using
块说我们已经完成了我们的工作,现在继续使用return
等其他内容是安全的。
答案 4 :(得分:0)
此警告可能与“单一退出点”的原则有关。这里讨论:http://c2.com/cgi/wiki?SingleFunctionExitPoint