C# CA2000:在失去作用域之前释放对象

4

这是我的代码,在“new DataTable()…” 和 “new DataColumn()…” 处出现了CA2000错误。

usersDS.Tables.Add(new DataTable()
{
    TableName = "Users",
    Columns = { new DataColumn() { ColumnName = "Handle", DataType = typeof(string) }, new DataColumn() { ColumnName = "Nickname" ,DataType = typeof(string) } }
});

不声明变量能否修复此问题?

1
在这种情况下,我认为代码看起来很好,我只会抑制警告。DataTableDataColumn都不持有任何非托管资源。另请参阅https://dev59.com/XnNA5IYBdhLWcg3wjOve - user743382
2
相关:https://dev59.com/yFnUa4cB1Zd3GeqPYTU_和https://dev59.com/im855IYBdhLWcg3wj1QS - Soner Gönül
1
@JasonEvans 它的基类有。DataTable 派生自 MarshalByValueComponent,而它实现了 IDisposable 接口。DataColumn 也是如此。 - user743382
1个回答

7
这几乎是如何在使用全局缓存时修复CA2000 IDisposable C#编译器警告的重复。也许它应该被认为是那个问题的重复。我不确定。
代码分析合理地抱怨,理论上可能会出现方法完成而未处理IDisposable对象并且未将其安全存储在其他位置的情况。如果DataTable对象初始化或将DataTable对象添加到usersDS.Table对象(无论它是什么)过程中发生异常,则可能会出现后一种情况。
如果您可以保证此处不会引发任何异常,则在我的意见中,完全可以忽略CA警告。在这种情况下,您比CA更了解情况,并承诺自己知道自己在做什么。
如果您不能做出保证,则没有办法在不引入局部变量的情况下解决警告,以便在发生异常时能够处理该对象。例如:
DataTable dataTable = null;
DataColumn dataColumn1 = null, dataColumn2 = null;

try
{
    dataColumn1 = new DataColumn() { ColumnName = "Handle", DataType = typeof(string) };
    dataColumn2 = new DataColumn() { ColumnName = "Nickname", DataType = typeof(string) };
    dataTable = new DataTable()
    {
        TableName = "Users",
        Columns = { dataColumn1, dataColumn2 }
    };
    usersDS.Tables.Add(dataTable);
}
catch
{
    if (dataTable != null)
    {
        dataTable.Dispose();
    }
    if (dataColumn1 != null)
    {
        dataColumn1.Dispose();
    }
    if (dataColumn2 != null)
    {
        dataColumn2.Dispose();
    }
    throw;
}

代码分析在合理地抱怨说,这个方法在没有处理 IDisposable 对象的情况下可能会完成。虽然这是可能的,但对于 Dispose() 没有实际影响的任何类来说,这不是一个合法的投诉。正如评论中所指出的那样,即使 DataTableDataColumn 实现了 IDisposable 接口,这并没有什么有用的作用,这些类应该被设计为不实现 IDisposable 接口。我们无法解决这个问题,但可以避免调用它们的 Dispose() 方法。 - user743382
2
DataTableDataColumn没有在IDisposable中实现任何有意义的操作,这是一个_实现细节_。也就是说,这不是DataTableDataColumn的合同的一部分,并且理论上可以在将来更改。我更喜欢编写公共合同而不是私有实现,并且在我看来,最好只是去处理IDisposable对象,而不管您了解其私有实现细节。你的情况可能有所不同。 - Peter Duniho
我假设usersDS被命名为usersDS是因为它是“用户”DataSet。如果这个假设是错误的,那么很抱歉。顺便说一下,你可能想在(再次)链接的问题上投票:得票最高的答案不同意你的观点,但其他几个答案则持相反意见。 - user743382
这可能是一个不错的假设。但就我而言,由于DataSetDataTableDataColumn之间非常密切的关系,这并不重要。在DataSet中良好的实现选择在用户代码中未必是良好的选择。 - Peter Duniho
我查看了您链接的问题的其他答案,确实有几个与我的立场相同。其中一个回答者在真实世界的代码中看到了不释放资源的危害:当 DataTable 对象由组件容器拥有时,除非您对其进行处理,否则它不会从容器中移除,导致无法进行垃圾回收。 - Peter Duniho
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接