存储在集合中的IDisposable对象是否应手动处理?

时间:2014-01-24 14:54:13

标签: c# .net collections stack idisposable

我有一堆WindowsImpersonationContext个对象,IDisposable类型。现在考虑这两个操作:

Stack<WindowsImpersonationContext> stack = new Stack<WindowsImpersonationContext>();

public void BeginOperation()
{
    // Push object to stack
    var context = WindowsIdentity.Impersonate(...);
    stack.Push(context);
}

public void EndOperation()
{
    // Pop object from stack.
    if (stack.Count != 0)
    {
        var context = stack.Pop();
        ... do various stuff with 'context' ...
        context.Dispose();  // should this be called once the object is not needed anymore?
    }
}

如果我不想等待GC执行此操作,是否应该手动调用Dispose()?如果我100%没有其他代码会尝试使用堆栈中引用的context对象,这样做是否安全?确切地说,如果我没有明确地调用context.Dispose(),我认为即使在执行从EndOperation()返回之后,我仍然受GC处理“上下文”所占用的资源的摆布'对象,尽管它不再被堆栈引用了?我的推理是否正确?

另外,使用上面的代码,声称在执行下面的一组操作之后,堆栈将在占用的资源方面结束为空(即它用于包含的所有对象都放在最后,并且我不需要担心在其他地方处理任何事情了):

BeginOperation();
  BeginOperation();
  EndOperation();
EndOperation();

编辑:我意识到using可以/应该用于安全目的,但主要是我关注收集/ GC背景中发生的事情,无论如何语法......

3 个答案:

答案 0 :(得分:2)

如果您确定堆栈以外的任何内容都没有引用相关对象,那么是:您应该自己手动处理它。

我会将您的代码更改为更像这样:

public void EndOperation()
{
    // Pop object from stack.
    if (stack.Count != 0)
    {
        using (var context = stack.Pop())
        {
            ... do various stuff with 'context' ...
        }
    }
}

即使在“do various stuff”块中发生异常,它也会被处理掉。

如果你不自己处理它,那么你依赖于为被处理的类实现的终结器 - 即使实现了终结器,也可能被称为太晚(想象一下它是否是一个打开的文件句柄)

答案 1 :(得分:2)

如果你不再需要它,它实现IDisposable使用using - 声明。

public void EndOperation()
{
    // Pop object from stack.
    if (stack.Count != 0)
    {
        using(var context = stack.Pop())
        {
            // ... do various stuff with 'context' ...
        }
    }
}

除了Stack.Pop以这种方式实现(ILSPy,.NET 4):

// System.Collections.Stack
public virtual object Pop()
{
    if (this._size == 0)
    {
        throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyStack"));
    }
    this._version++;
    object result = this._array[--this._size];
    this._array[this._size] = null;
    return result;
}

所以你看到Pop后堆栈中不再有引用了。

通常,只要您使用非托管资源,就应该使用using(或try-finally)。通过这种方式可以确保它们在出错时处理。

答案 2 :(得分:1)

您可以使用using语句,但应该先实现IDisposable