可处理对象的标准集合

14

我有一些 IDisposable 对象存储在一个查找表中(目前使用的是普通的 Dictionary<>),但为了简化代码和避免错误,我正在寻找拥有其所持有的项目的集合类,并且为了避免重复造轮子 - 是否已经存在这样的类?

规格应该是: - 集合必须是可释放的,当它被释放时,所有包含的项目也应该被释放。 - 每当删除项时,应该先进行 Dispose()。 - 理想情况下,集合应该是泛型的,并通过类型约束强制实施所包含的类型的 IDisposable

我有点怀疑是否存在这样的类,但以前我对 ReadOnlyCollectionObservableCollection 的存在感到惊喜......

本质上,我想要与 C++ STL 容器等效的东西,但适用于 CLR ;-).


有一段时间了,你做了一个IDisposableCollection吗?我也可以用一下。 - JohnV
不,我最终将集合封装起来,仅暴露了我实际需要的(非常少的)方法 - 添加/获取/删除 - 以及一些特定工作所需的其他功能(大量文件系统监视器)。 - Eamon Nerbonne
5个回答

9
你正在寻找与 CompositeDisposable 相关的内容。
    using System.Reactive.Disposables;

    ...

    CompositeDisposable xs = new CompositeDisposable(Disposable.Empty);
    xs.Add(Disposable.Empty);
    xs.Add(Disposable.Empty);
    xs.Dispose();

1
非泛型。这不是完美的选择,但也不是什么大问题。 - Eamon Nerbonne
1
Rx扩展不是.NET框架的一部分。虽然对于许多人来说这不是问题,但为了一个微不足道的类而引用整个库并不是一个好主意。 - arbiter
@arbiter 有一点道理,尽管在我看来,不使用 Rx 没有太多意义。一旦你决定在项目中引入使用 .net 的巨大开销,就没有人应该对引入有用的库提出异议。 - James Moore

3
据我所知,仅有一个IComponents的集合存在 - Container实现了IContainer。对于通用的IDisposable,我认为你没有其他选择,只能“重新发明轮子”。

谢谢,我会研究一下(尽管看起来有一些繁琐 - API 有很多我不会使用的东西 - 但这可能并不重要)! - Eamon Nerbonne
容器(Container)和系统组件模型(System.ComponentModel)似乎过于复杂,且不够灵活以供一般使用。简而言之,我接受你的答案,即我别无选择,只能“重新发明轮子”。 - Eamon Nerbonne

3
像这样怎么样:
public class DisposableEnumerable<T> : IEnumerable<T>, IDisposable where T : IDisposable
{
    IEnumerable<T> Enumerable { get; }

    public DisposableEnumerable(IEnumerable<T> enumerable)
    {
        Enumerable = enumerable;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return Enumerable.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return Enumerable.GetEnumerator();
    }

    public void Dispose()
    {
        foreach(var disposable in Enumerable)
        {
            disposable.Dispose();
        }
    }
}

我认为在这里将一个惰性枚举作为参数至少有些棘手;重要的是要知道你传递的对象是否真正被处理。当然,如果集合没有被修改,那就没关系了。 - Eamon Nerbonne
另外,即使不应该发生,您也应该考虑如果底层的 Dispose() 抛出异常会发生什么。 - Eamon Nerbonne

1

请记住,您的集合可能不是唯一包含可丢弃对象的集合...

如果另一个对象(不属于该集合)正在引用其中之一,那怎么办?如果在处理集合时将其处理掉,则该对象会发生什么?

如果这些对象为了清理非托管资源而实现了IDisposable,则请确保它们也实现了终结器并在那里处置非托管资源。


我目前完全控制着对象和集合 - 所以这只是一种假设情况。无论如何,这就是IDisposable的工作方式,对吧?我的意思是,某人必须拥有(即最终Dispose)它们,在这种情况下,所有者恰好拥有可变数量的IDisposables,因此集合会是最简单的选择。 - Eamon Nerbonne

0

我明白你的问题,但是自己编写一个删除方法,在删除元素之前将其处理掉有多难呢?


不难,但如果可能的话最好避免。而且,这不仅仅是Remove方法 - 任何可能覆盖元素的方法都会隐式替换现有元素,这也需要Dispose()。如果您的集合实现了一些标准接口,那么这些remove/setter函数就会有很多变体,导致代码膨胀。 - Eamon Nerbonne
https://blog.stephencleary.com/2009/08/third-rule-of-implementing-idisposable.html + https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About + 像SonarQube这样的工具往往会在你按照完整的旧模式进行操作之前频繁抱怨。 - quetzalcoatl
https://blog.stephencleary.com/2009/08/third-rule-of-implementing-idisposable.html + https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About + 像SonarQube这样的工具往往会在你遵循完整的旧模式之前抱怨很多。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接