我的代码是否正确清理了其列表?
-
20-08-2019 - |
题
我有一个执行PDF文件操作的第三方组件。每当我需要执行操作时,我都会从文档存储(数据库,SharePoint,Filesystem等)中检索PDF文档。为了使事情变得有些一致,我将PDF文档作为一个 byte[]
.
这个第三方组件期望 MemoryStream[]
(MemoryStream
数组)作为我需要使用的主要方法之一的参数。
我正在尝试将此功能包裹在自己的组件中,以便可以在应用程序中的许多区域中使用此功能。我已经想出以下内容:
public class PdfDocumentManipulator : IDisposable
{
List<MemoryStream> pdfDocumentStreams = new List<MemoryStream>();
public void AddFileToManipulate(byte[] pdfDocument)
{
using (MemoryStream stream = new MemoryStream(pdfDocument))
{
pdfDocumentStreams.Add(stream);
}
}
public byte[] ManipulatePdfDocuments()
{
byte[] outputBytes = null;
using (MemoryStream outputStream = new MemoryStream())
{
ThirdPartyComponent component = new ThirdPartyComponent();
component.Manipuate(this.pdfDocumentStreams.ToArray(), outputStream);
//move to begining
outputStream.Seek(0, SeekOrigin.Begin);
//convert the memory stream to a byte array
outputBytes = outputStream.ToArray();
}
return outputBytes;
}
#region IDisposable Members
public void Dispose()
{
for (int i = this.pdfDocumentStreams.Count - 1; i >= 0; i--)
{
MemoryStream stream = this.pdfDocumentStreams[i];
this.pdfDocumentStreams.RemoveAt(i);
stream.Dispose();
}
}
#endregion
}
我的“包装器”的调用代码看起来像这样:
byte[] manipulatedResult = null;
using (PdfDocumentManipulator manipulator = new PdfDocumentManipulator())
{
manipulator.AddFileToManipulate(file1bytes);
manipulator.AddFileToManipulate(file2bytes);
manipulatedResult = manipulator.Manipulate();
}
关于上述问题的一些问题:
- 是个
using
子句AddFileToManipulate()
方法冗余和不必要吗? - 我是否在对象中清理一切正常
Dispose()
方法? - 这是一种“可接受”的用法
MemoryStream
?我不会预料到一次内存中有很多文件...可能是1-10个PDF页面,每个页面约为200kb。旨在在支持ASP.NET站点的服务器上运行的应用程序。 - 有评论/建议吗?
感谢您的代码审查:)
解决方案
- AddFileTomanipulate()方法中的使用子句是冗余和不必要的吗?
更糟糕的是,这是破坏性的。您基本上要在添加内存流之前关闭它。有关详细信息,请参见其他答案,但基本上是在最后处置,但没有其他时间。即使对象通过方法“传递”到其他对象,每次使用对象都会导致处置发生在块的末端。
- 我是否在对象的dispose()方法中清理好东西?
是的,但是您使生活比需要的更加困难。尝试这个:
foreach (var stream in this.pdfDocumentStreams)
{
stream.Dispose();
}
this.pdfDocumentStreams.Clear();
这也是如此,而且更简单。处理对象不会删除它 - 它只是告诉它释放其内部,不受管理的资源。以这种方式呼叫在对象上处置是可以的 - 集合中的对象保持未收集。您可以执行此操作,然后一枪清除列表。
- 这是对内存流的“可接受”用法吗?我不会预料到一次内存中有很多文件...可能是1-10个PDF页面,每个页面约为200kb。旨在在支持ASP.NET站点的服务器上运行的应用程序。
这取决于您的情况。只有您才能确定将这些文件存储在内存中的开销是否会导致您的问题。但是,这将是一个相当重量的对象,所以我会仔细地使用它。
- 有评论/建议吗?
实现最终制度。每当您实现Idisposable时,这都是一个好主意。另外,您应该将处置实施方式重新设计为标准的实施方式,或将您的班级标记为密封。有关如何完成此操作的详细信息, 请参阅本文。 特别是,您应该有一种方法称为 protected virtual void Dispose(bool disposing)
您的处置方法和最终制度都致电。
其他提示
加上filetomantulation让我感到恐惧。
public void AddFileToManipulate(byte[] pdfDocument)
{
using (MemoryStream stream = new MemoryStream(pdfDocument))
{
pdfDocumentStreams.Add(stream);
}
}
此代码将doved流的流添加到您的pdfdocumentstream列表中。相反,您应该简单地使用以下方式添加流。
pdfDocumentStreams.Add(new MemoryStream(pdfDocument));
并在处理方法中处置它。
另外,您应该考虑实现最终制度,以确保在某人忘记处置顶级对象的情况下被处置。
在我看来,就像您误解了使用什么一样。
只是句法糖代替
MemoryStream ms;
try
{
ms = new MemoryStream();
}
finally
{
ms.Dispose();
}
您对Addfiletomansulation的使用是多余的。我将在PDFDocumentManipulator的构造函数中设置MemoryStream的列表,然后在所有内存流上都有PDFDocumentManipulator的Dispose Dispose方法Dispose。
边注。这似乎确实需要扩展方法。
public static void DisposeAll<T>(this IEnumerable<T> enumerable)
where T : IDisposable {
foreach ( var cur in enumerable ) {
cur.Dispose();
}
}
现在您的处理方法变成了
public void Dispose() {
pdfDocumentStreams.Reverse().DisposeAll();
pdfDocumentStreams.Clear();
}
编辑
您不需要3.5框架就可以使用扩展方法。他们将很乐意处理针对2.0的3.0编译器
http://blogs.msdn.com/jaredpar/archive/2007/11/16/extension-methods-without-3-5-framework.aspx