【问题标题】:How to properly dispose objects created with LINQ如何正确处理使用 LINQ 创建的对象
【发布时间】:2011-02-23 18:37:19
【问题描述】:

我有以下创建一次性对象实例的方法。

Public Overridable Sub TransformXmlDocumentsToFileStream(ByVal stream As System.IO.Stream, ByVal xmlDocuments As IEnumerable(Of String), ByVal transformContext As XslTransformContext)
    Dim readers As IEnumerable(Of XmlReader) = _
        (From document In xmlDocuments _
         Select XmlReader.Create(New System.IO.StringReader(document)))

    With transformContext
         TransformXmlDocumentsToFileStream(stream, readers, transformContext)
    End With
End Sub

然后我用另一种方法遍历对象:

For Each reader In readers
    Using reader
        transform.Transform(reader, writer)
    End Using
Next

Visual Studio 代码分析器发出警告:

CA2000:Microsoft.Reliability:在方法“TransformHelper.TransformXmlDocumentsToFileStream(Stream, IEnumerable(Of String), XslTransformContext)”中,对象“New StringReader(document)”并未沿所有异常路径进行处理。在对对象“New StringReader(document)”的所有引用超出范围之前调用 System.IDisposable.Dispose。

由于没有对StringReader 的引用,我不能将它放在 using 块中或以其他方式处理它。可以忽略此警告吗? StringReader 应该在阅读器超出范围并被垃圾收集时释放,对吗?

【问题讨论】:

标签: .net linq dispose idisposable


【解决方案1】:

对不起c#中的答案。管理 IDisposables 的一种简单方法是使调用 new 的方法也调用 Dispose。

List<StringReader> stringReaders = new List<StringReader>();
  //note: Select is deferred.  stringReaders is captured.
IEnumerable<XmlReader> readers =
  xmlDocuments.Select(document =>
  {
    StringReader sr = new System.IO.StringReader(document);
    stringReaders.Add(sr);
    return XmlReader.Create(sr);
  });
try
{
  //this method enumerates readers, causing all of the allocations.
  TransformXmlDocumentsToFileStream(stream, readers, transformContext);
}
finally
{
  foreach(StringReader x in stringReaders)
  {
    x.Dispose();
  }
}

【讨论】:

  • 不用担心C#,我很了解。我希望我可以在我的环境中使用它。太糟糕了,它们不是可以挂钩的事件(OnSelect 或 OnEnumerate),因此可以在迭代期间进行处置。感谢您的解决方案。
【解决方案2】:

Dispose 在对象碰巧被垃圾回收时调用,这可能永远不会或在对象超出范围后很长时间。你应该明确地处理你的StringReaders。

如果我的 VB 正确,你可以这样做

    Dim stringReaders As IEnumerable(Of System.IO.StringReader) = _
        (From document In xmlDocuments _
         Select New System.IO.StringReader(document)).ToList()

    Try
        Dim readers As IEnumerable(Of XmlReader) = _
            (From stringReader In stringReaders _
             Select XmlReader.Create(stringReader))
        With transformContext
            TransformXmlDocumentsToFileStream(stream, readers, transformContext)
        End With

    Finally
        For Each stringReader In stringReaders
            stringReader.Dispose()
        Next
    End Try

【讨论】:

  • 我在这里可能是错的,但最后你会不会建议重新创建所有字符串阅读器,因为这是第二次循环遍历可枚举?我相信@David B 的解决方案通过将读者存储在单独的列表中来排除这种情况。
  • @Richard,不,.ToList() 确保创建只完成一次。
  • 啊,是的,对不起。我没有看到,也没有考虑它,因为我特别想不这样做。在这种情况下,xmlDocuments 本身就是 dataReader 上的另一个 IQueryable(我为 dataReader 编写了一个 IEnumerable/IEnumerator 包装器)。我不想一次获取列表中的所有文档,以免分配大块内存。
猜你喜欢
  • 1970-01-01
  • 2020-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-26
相关资源
最近更新 更多