处理列表的最佳方式

Viv*_*ekh 31 c# asp.net garbage-collection dispose list

我有List对象.我该如何处理清单?

例如,

List<User> usersCollection =new List<User>();

User user1 = new User();
User user2 = new User()

userCollection.Add(user1);
userCollection.Add(user2);
Run Code Online (Sandbox Code Playgroud)

如果我确定userCollection = null;会发生什么?

foreach(User user in userCollection)
{
    user = null;
}
Run Code Online (Sandbox Code Playgroud)

哪一个最好?

Cor*_*ius 24

最好的想法是把它留给垃圾收集器.您foreach将不做任何事情,因为只有参考将被设置为null不是列表中的元素.将列表设置为null实际上可能导致垃圾收集发生的时间比它可能的要晚(参见本文C#:应该将对象变量赋值为null吗?).

  • 您链接了整个线程。您能否更具体地说明为什么在这种情况下以后会发生垃圾回收?甚至引用相关段落。 (2认同)
  • 这取决于您存储在集合中的对象的类型。如果其中一些实现了IDisposable,则设计人员希望鼓励您调用IDisposable.Dispose(),而不仅仅是让垃圾收集器为您执行此操作。通常这是因为资源不足。例如,如果一次仅一个对象可以使用一台摄像机,则仅分配null不会立即释放摄像机,而调用Dispose()可以做到这一点。 (2认同)

Mar*_*ell 19

首先,你不能"处置"一个列表,因为它不是IDisposable,你不能强制它被收集,因为这不是C#的工作方式.通常你在这里什么都不做.所以,当可能,我们需要做什么

  • 如果它是方法变量,并且您的方法稍后将退出,请不要执行任何操作:让GC在方法存在后的某个时刻担心它.
  • 如果它是一个字段(实例变量),并表示即将走出去的范围在某一时刻,没有做任何事情:让这件事的GC担心在某一点之后实例不可达.

你需要的只是时间任何事情是,如果它是一个场(或捕获变量/迭代器块可变/等)实例(/代理/迭代器)是要活得长一段时间-那么也许设置列表字段为空.但请注意,如果任何其他代码仍然具有对列表的引用,那么仍然可以访问所有内容.

  • @HaraldDutch"处理列表"和"处理列表中的项目"之间存在差异.该列表通常无权假定它是这些对象的唯一所有者. (5认同)
  • 如果您不再需要列表中的对象,我不同意您不应该做任何事情.如果对象实现System.IDisposable接口,则对象的设计者认为该对象包含稀缺资源.如果您不需要它并且只为对象分配null,那么在垃圾收集器完成对象之前,不会释放这些稀缺资源.与此同时,您无法将此资源用于其他内容. (3认同)

Har*_*lse 17

如果您不再需要列表中的对象,我不同意您不应该做任何事情.如果对象实现了接口,System.IDisposable则对象的设计者认为该对象拥有稀缺资源.

如果您不再需要该对象并且只为对象分配null,则在垃圾收集器完成对象之前,不会释放这些稀缺资源.与此同时,您无法将此资源用于其他内容.

示例:考虑从文件创建位图,并确定您既不需要位图也不需要文件.代码如下所示:

using System.Drawing;
Bitmap bmp = new Bitmap(fileName);
... // do something with bmp until not needed anymore
bmp = null;
File.Delete(fileName); // EXCEPTION, filename is still accessed by bmp.
Run Code Online (Sandbox Code Playgroud)

好方法是:

bmp.Dispose();
bmp = null;
File.Delete(fileName);
Run Code Online (Sandbox Code Playgroud)

对列表中的对象或任何集合进行相同的说明.应该处理集合中IDisisable的所有对象.代码应该像:

private void EmptySequence (IEnumerable sequence)
{   // throws away all elements in the sequence, if needed disposes them
    foreach (object o in sequence)
    {
        System.IDisposable disposableObject = o as System.IDisposable;
        o = null;
        if (disposableObject != null)
        {
            disposableObject.Dispose();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果要创建IEnumerable扩展函数

public static void DisposeSequence<T>(this IEnumerable<T> source)
{
    foreach (IDisposable disposableObject in source.OfType(System.IDisposable))
    {
        disposableObject.Dispose();
    };
}
Run Code Online (Sandbox Code Playgroud)

所有列表/字典/只读列表/集合/等都可以使用这些方法,因为它们都实现了IEnumerable接口.如果并非序列中的所有项都实现System.IDisposable,您甚至可以使用它.


jhe*_*ngs 13

这篇文章的另一个想法......如果你想确保集合的所有成员都得到妥善处理,你可以使用以下扩展方法:

public static void DisposeAll(this IEnumerable set) {
    foreach (Object obj in set) {
        IDisposable disp = obj as IDisposable;
        if (disp != null) { disp.Dispose(); }
    }
}
Run Code Online (Sandbox Code Playgroud)

这将查看实现IDisposable和处理它的任何成员的集合.从执行代码中,您可以像这样清理列表:

usersCollection.DisposeAll();
usersCollection.Clear();
Run Code Online (Sandbox Code Playgroud)

这将确保所有成员都有机会释放资源,结果列表为空.