多次处置对象

我有以下代码,它使用流来打开和修改Open XML文档,然后保存该流的新二进制表示:

MemoryStream stream = null; try { stream = new MemoryStream(); stream.Write(this.GetBinaryRepresentation(), 0, this.GetBinaryRepresentation().Length); using (WordprocessingDocument document = WordprocessingDocument.Open(stream, true)) { OfficeDocument.ModifyDocument(document); this.SetBinaryRepresentation(stream.ToArray()); stream = null; } } finally { if (stream != null) { stream.Dispose(); } } 

我最初使用了两个使用块(一个用于MemoryStream,第二个用于WordprocessingDocument),但收到警告CA2202:“对象’流’可以在方法中多次丢弃…”根据MSDN文章 ,我修改了上面的代码(将外部使用转换为试用),但我仍然收到此警告。

我不确定如何构造此方法以确保在流上只调用一次Dispose。 我不想简单地抑制此警告,因为MSDN文章声明您不应该依赖Dispose多次安全地调用。

MSDN文章中的示例不适用于您的原因是它们在进入using块时将流设置为null,而您使用using块内的流并将流设置为null。 如果在stream = null语句之前抛出exception,则在退出using块时将丢弃stream ,然后在finally块中再次处理。

不幸的是,由于您需要在document更新之后访问您的流,我没有看到一种干净的方法来使用他们在您的using语句中设置stream = null的示例来避免多次Dispose()调用。 另一种方法是你可以在try块之外声明streamdocument ,然后在finally中清除它们,如下所示:

 MemoryStream stream = null; WordprocessingDocument document = null; try { stream = new MemoryStream(); stream.Write(this.GetBinaryRepresentation(), 0, this.GetBinaryRepresentation().Length); document = WordprocessingDocument.Open(stream, true)); OfficeDocument.ModifyDocument(document); this.SetBinaryRepresentation(stream.ToArray()); } finally { if( document != null) { document.Dispose(); } // Catch the case where an error occurred before document was defined. else { stream.Dispose(); } } 

多次处理物体应始终是安全的。 从Dispose的文档 :

如果多次调用对象的Dispose方法,则该对象必须忽略第一个之后的所有调用。 如果多次调用Dispose方法,则该对象不得抛出exception。

话虽这么说,使用声明绝对是这里的方式。 您收到该方法的唯一原因是,如果您明确处置了不需要的对象,因为using语句应该始终只处理一次对象。

如果在将流设置为空之前在使用块中抛出exception,则流仍可被丢弃两次。 试试这个:

 MemoryStream stream = null; MemoryStream streamToDispose = null; try { streamToDispose = stream = new MemoryStream(); stream.Write(this.GetBinaryRepresentation(), 0, this.GetBinaryRepresentation().Length); using (WordprocessingDocument document = WordprocessingDocument.Open(stream, true)) { streamToDispose = null; OfficeDocument.ModifyDocument(document); this.SetBinaryRepresentation(stream.ToArray()); } } finally { if (streamToDispose != null) { streamToDispose.Dispose(); } } 

using语句处理对象 – 所以基本上你调用dispose两次

当您的代码在WordProcessingDocument周围离开使用块时,它将调用dispose。

 using (WordprocessingDocument document = WordprocessingDocument.Open(stream, true)) 

由于WordProcessingDocument在其构造函数中获取流的实例,因此在调用WordProcessingDocument.Dispose时,它将在该流实例上调用dispose。 然后输入您调用stream.Dispose()的finally块 – 您现在已在流实例上调用两次Dispose()。