4

我有以下代码,它使用流打开和修改 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();
    }
}

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

我不确定如何构建此方法以确保在流上仅调用一次 Dispose。我不想简单地禁止这个警告,因为 MSDN 文章指出你不应该依赖 Dispose 可以安全地多次调用。

4

5 回答 5

6

多次处理一个对象应该始终是安全的。从Dispose 的文档中

如果多次调用对象的 Dispose 方法,则对象必须忽略第一次调用之后的所有调用。如果多次调用其 Dispose 方法,则该对象不得引发异常。

话虽这么说,使用语句绝对是这里的方法。您收到该方法的唯一原因是您明确处置对象,这不是必需的,因为 using 语句应始终仅处置对象一次。

于 2012-06-25T15:38:22.643 回答
3

如果在将流设置为 null 之前在 using 块中引发异常,则流仍可能被释放两次。试试这个:

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();
    }
}
于 2012-06-25T15:39:55.233 回答
3

MSDN文章中的示例对您不起作用的原因是他们在进入 using 块后立即将流设置为 null,而您在 using 块中使用流并在之后将流设置为 null 。stream = null如果在您的语句之前抛出异常,stream将在退出 using 块时处理,然后在您的 finally 块中再次处理。

不幸的是,由于您需要在document更新后访问您的流,因此我看不到一种干净的方法可以stream = null在您的 using 语句中使用他们的设置示例来避免多次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();
    }
}
于 2012-06-25T16:01:26.903 回答
2

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

于 2012-06-25T15:37:47.823 回答
0

当您的代码将 using 块留在 周围时WordProcessingDocument,它将调用 dispose。

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

由于在其构造函数中WordProcessingDocument接受了一个实例stream,因此它会在调用该流实例时调用 dispose WordProcessingDocument.Dispose。然后你进入你调用的 finally 块stream.Dispose()——你现在在流实例上调用了 Dispose() 两次。

于 2012-06-25T15:58:39.613 回答