我无法解决代码分析规则CA2202的问题。

4

我有一个功能(见下面的代码片段)。

我启用了代码分析,但是我收到了CA2202规则违规的警告。

编辑:我添加了pdfStamper的关闭操作,否则PDF文件将会损坏)

CA2202:不要多次处理对象

一个方法实现包含可能导致在同一对象上调用IDisposable.Dispose或Dispose等效项(例如某些类型的Close()方法)的多个调用的代码路径。

在CA2202 MSDN页面(这里),所提出的解决方案并不可行。

如何重写代码而无需抑制此违规?

private byte[] DoGenerateFinishedGamePdf(int gameSessionLogId)
{
   var finishedGameCertificatePdfFile = httpServerUtilityWrapper.MapPath(ConfigurationManager.AppSettings["FinishedGameCertificateFile"]);

   var pdfReader = new PdfReader(finishedGameCertificatePdfFile); // note that PdfReader is not IDisposeable

   using (MemoryStream memoryStream = new MemoryStream())
   using (PdfStamper pdfStamper = new PdfStamper(pdfReader, memoryStream))
   {
      var fields = pdfStamper.AcroFields;
      fields.SetField("CityName", "It works!");

      pdfReader.Close();

      pdfStamper.FormFlattening = true;
      pdfStamper.FreeTextFlattening = true;
      pdfStamper.Close();

      return memoryStream.ToArray();
   }
}

这很奇怪。我使用using来处理一次性对象,但我从未收到过Dispose警告。你是在处理memoryStream或pdfStamper时收到的警告吗? - fhnaseer
2个回答

2
啊,大家都喜欢的警告!在这种情况下,MemoryStream.Dispose是幂等的(当前实现不执行任何操作),因此这并不是真正的问题,但“修复”如下所示:
MemoryStream memoryStream = null;
try
{
  memoryStream = new MemoryStream();
  using (PdfStamper pdfStamper = new PdfStamper(pdfReader, memoryStream))
  {
    memoryStream = null;

    var fields = pdfStamper.AcroFields;
    fields.SetField("CityName", "It works!");

    pdfReader.Close();

    pdfStamper.FormFlattening = true;
    pdfStamper.FreeTextFlattening = true;
    pdfStamper.Close();

    return memoryStream.ToArray();
  }
}
finally
{
  if (memoryStream != null) memoryStream.Dispose();
}

由于PdfStamper“拥有”MemoryStream,因此在调用PdfStamper.Dispose时它将对其进行处理,因此我们只需要在未处理PdfStamper的情况下调用MemoryStream上的Dispose,而这只会在PdfStamper构造失败时发生。


代码片段无法编译,因为您重新声明了MemoryStream。如果我通过删除类型名称来修复此问题,我会在第5行收到CA2000错误:'在所有引用超出范围之前调用System.IDisposable.Dispose对象'memoryStream' - Patrick Peters
我忘记在我的代码中添加pdfStamper = new PdfStamper(pdfReader,memoryStream)从您的代码示例中,并且现在我收到3个警告:一个是在创建memoryStream时的CA2000,两个是在finally块中的每个Dispose上的CA2202...请注意,我编辑了原始问题,在pdfStamper完成其工作后添加了一行代码(使用close)。 - Patrick Peters
@PatrickPeters 在最新的编辑中,finally 块之前 psfStamper 将超出范围... 只需检查 finally 块是否仅包含对内存流(如果不为 null)的 dispose?可能值得进行清理和编译。 - Rich O'Kelly
在 stamper 上使用 Close() 是必要的,否则 PDF 文件将会损坏(我之前测试过了)。我现在会在代码中抑制这些调用,并在 Itextsharp 论坛上通知此事。 - Patrick Peters
当前版本会在return处引发NullReferenceException异常。 - Mark Hurd
显示剩余3条评论

1
这是由于PdfStamper即使不应该将其处置,仍在处置流。它没有创建它,也不拥有它,因此没有理由处置它。
您的代码确实创建了流并拥有它,因此应该自然地处置它。如果PdfStamper未适当地处置流,则使用嵌套的using将一切都变得很好。
您的第一步应该是提交错误报告/功能请求,要求删除或至少避免PdfStamper对流的处置。完成后,您可以相当安全地抑制CA2202违规,因为MemoryStream的双重处置不会产生有害后果。
顺便说一下,PdfStamper.Dispose()调用PdfStamper.Close()(至少在版本5.4.0中),因此您应该能够删除PdfStamper.Close()调用。

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