我是否应该编写返回可释放实例列表的方法?

6

我有一个类,其实例需要被处理。我还有几个类,可以单独或以列表的形式生成这些实例。

我的方法应该返回IList<MyClass>还是应该创建一个名为MyClassCollection的可处理类,并返回它呢?

编辑:

我提出问题的主要原因是我经常会做这样的事情:

IList<MyObject> list = GetList();
foreach(MyObject obj in list)
{
     //do something
     obj.Dispose();
} 

看起来我最好做的是:

using (IList<MyObject> list = GetList())
{
     foreach(MyObject obj in list)
     {
     //do something

     } 
}

你的第一个例子在不再需要对象时立即处理它们,但第二个例子会一直保持对象存活,直到整个迭代完成。这是两种不同的处理对象的方式,你应该根据哪种更合适来选择要使用的方法。 - Mark Byers
5个回答

3

生成一个项目的序列(IEnumerable<T>)可能比生成列表更容易 - 有一些方法可以使每个项目的生命周期与迭代器绑定,以便:

  • 您一次只有一个(我假设它们很昂贵)
  • 它们在时间到期时被处理
  • 即使出现错误,它们也都被处理

这是一个我用LINQ探索的主题here,但如果您的源是(或可以)一个序列,还有其他方法。


2

这取决于你如何使用它们,两种选择似乎都合理。如果你知道需要同时处理所有对象,那么使列表可处理可能是有意义的,但如果对象的生命周期可能不同,我会返回普通的列表。

也许你可以制作一个通用的IDisposableList<T>,其中对T有一个约束条件where T : IDisposable,并且通过调用其元素上的Dispose,来实现您的类实现IDisposable?然后,您可以将此类重复使用于所有不同的IDisposable类型。


@bebop:我认为如果你选择使用可处理的列表,对于你目前的情况可能会更方便一些,但是你暗示了你的客户端应该同时处理这些对象。是否有根本原因要求这些对象必须同时被处理?是否可以通过拥有一个需要处理的资源来以不同的方式进行建模?你的情况让我想起了连接和事务,或者具有多个读取器的文件。也许你可以将这些类用作设计灵感? - Mark Byers

2

完全由客户端代码调用您的Dispose()方法。只有它知道何时停止使用对象。您无法提供任何帮助,因为您不知道该代码的样子。创建释放其元素的列表对象不是一个好主意。框架中没有执行此操作的集合对象。这只会让客户端代码程序员感到困惑。


1
嗯,有趣。我想可能存在一些情况,其中列表中的某些元素将返回给另一个方法,然后处理列表可能会导致问题。 - Sam Holder

1
一个容器类在这些情况下可能更加清晰。你可以继续使用标准的集合类,并且你被迫更加明确地说明项目何时需要在结束时进行处理。
public class ListScope : IDisposable
{
    private IList list;
    public ListScope(IList list)
    {
        this.list = list;
    }

    #region IDisposable Members

    public void Dispose ()
    {
        foreach ( object o in this.list )
        {
            IDisposable disposable = ( o as IDisposable );
            if (disposable != null)
                    disposable.Dispose ();
        }
    }

    #endregion
}

你可以使用以下方式:

using ( new ListScope ( list ) )
{
   // Do stuff with list
}

你为什么要使用 'if (o is IDisposable) { (o as IDisposable).Dispose(); }'?为什么不直接使用 'o as IDisposable' 然后测试是否为空? - thecoop
@thecoop 我真的不太明白我会从那种方法中获得什么。我要么必须使用一个临时变量,要么执行 if ((o as IDisposabe) != null) {(o as IDisposable).Dispose()}。我觉得这种方式更加简洁,但你可以随意选择任何一种方式,我认为它们之间没有太大区别。 :) - Mongus Pong
我认为一个双重括号(o作为IDisposable)会触发静态代码分析规则,表示您应该为此创建一个变量,以避免不必要的重复强制转换。(对吗?) - peSHIr
是的,我认为这里有不必要的转换,按照thecoops的方式做似乎更好,即使需要一个临时变量。 - Sam Holder
有几个答案都可以作为答案的候选,但我认为这个最适合我的需求。当我想要处理列表时,我可以使用它,而当我不想处理时,我可以保持现状。谢谢! - Sam Holder

1

如果你想的话,也可以使用扩展:

static class Extensions
{
 public static void DoStuffAndDisposeElements<T> ( this List<T> list, Action<T> action )
 {
        list.ForEach ( x => { action ( x );
               IDisposable disposable = (x as IDisposable);
               if ( disposable != null )
                  disposable.Dispose ();

        } );
 }


}

你可以通过以下方式调用:

getList().DoStuffAndDisposeElements ( x => doStuff(x));

不确定你会从中获得多少好处,但在某些情况下可能会很有用;)


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