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();
   }
}
4

2 回答 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 的构造失败时发生.

于 2013-04-05T09:11:38.667 回答
1

发生这种情况是因为 PdfStamper 正在处理流,即使它不应该。它没有创造它,也没有拥有它,所以它没有处理它的业务。

您的代码确实创建了流并且它确实拥有它,因此它应该处理它是很自然的。如果 PdfStamper 没有不恰当地处理流,那么您的嵌套使用一切都会好起来的。

您的第一步可能应该是提交错误报告/功能请求,要求删除或至少可以避免流的 PdfStamper 处置。完成此操作后,您可以非常安全地抑制 CA2202 违规,因为 MemoryStream 的双重处置不会产生有害后果。

顺便说一句, PdfStamper.Dispose() 调用 PdfStamper.Close() (至少在版本 5.4.0 中),所以你应该能够删除 PdfStamper.Close() 调用。

于 2013-04-05T16:13:03.170 回答