Skip to main content
 首页 » 编程设计

c#之存储在集合中的 IDisposable 对象是否应该手动处理

2024年02月01日27telwanggs

我有一堆 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,不管语法...

请您参考如下方法:

如果您不再需要它并且它实现了 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)。通过这种方式,可以确保即使出现错误也能处理它们。