我可以一次处理多个对象吗

本文关键字:对象 处理 一次 我可以 | 更新日期: 2023-09-27 18:27:14

我有一个类Instance,它实现了如下所示的IDisposable接口。

class Instance : IDisposable
{
    //something
    void Dispose()
    {
        //Disposes something
    }
}

现在,在实际的代码中,我有几个实例需要在Finally块中处理,如下面

 finally
        {
            if (inst1 != null)
            {
                inst1.Dispose();
                inst1 = null;
            }
            if (inst2 != null)
            {
                inst2.Dispose();
                inst2 = null;
            }
            if (inst3 != null)
            {
                inst3.Dispose();
                inst3 = null;
            }
        }

所以每次我想要Dispose时,我都必须为每个对象写上面的行。

我觉得我可以使用"params"关键字来减少编号LOC(代码行),就像下面的一样

   static void DisposeInstance(params Instance[] instances)
    {
        for (int i = 0; i < instances.Length; i++)
        {
            if (instances[i] != null)
            {
                instances[i].Dispose();
                instances[i] = null;
            }
        }
    }

并在类似的单次发射中通过实例

 DisposeInstance(inst1, inst2, inst3);

但是上面的函数将只处理实例的本地副本,而不完全处理实际对象(实例)。

所以我的问题是,如果有任何方法可以实现我的目标,即一次性处理对象并减少LOC。

此外,我可以将"ref"关键字与"params"一起使用吗(我知道这会导致编译错误),但不知何故,将两者混合以获得结果?

提前感谢!

我可以一次处理多个对象吗

您不需要将对象设置为null,使用C#可以使用null传播语法:

inst1?.Dispose();
inst2?.Dispose();
inst3?.Dispose();

这大大降低了噪音。

您可以将列表传输到您的方法

   static void DisposeInstancies(List<Instance> instances)
    {
        for (int i = 0; i < instances.Length; i++)
        {
            if (instances[i] != null)
            {
                instances[i].Dispose();
                instances[i] = null;
            }
        }
    }

因此:

DisposeInstancies(new List<Instance> {inst1, inst2, inst3});

您可以尝试使用using语句,该语句将自动处理对象。类似这样的东西:

using (MyClass inst1 = new MyClass())
using (MyClass1 inst2 = new MyClass1())
using (MyClass2 inst3 = new MyClass2())
{
    // code 
}  

using语句允许程序员指定使用资源应该释放它们。提供给使用的对象语句必须实现IDisposable接口。此接口提供了Dispose方法,该方法应释放对象的资源。

但是上面的函数将只处理实例的本地副本,而不完全处理实际对象(实例)。

它处理对象(或者至少调用方法Dispose()),但在调用方作用域中没有将引用设置为null。实际上,在DisposeInstance作用域中,只有引用的复制值被设置为null。

你真的需要将其设置为null吗?如果您的目标是避免由于多次调用Dispose()而导致的错误,那么您应该使用布尔值来控制状态:

private bool hasBeenDisposed ; 
public void Dispose() 
{
    if (!hasBeenDisposed)
    {
        DisposeInstance(inst1, inst2, inst3);
        hasBeenDisposed = true ; 
    }
}

此外,为了提高可重用性和可读性,您应该将DisposeInstance参数更改为IDisposable []

static void DisposeInstance(params IDisposable [] instances)
{
    for (int i = 0; i < instances.Length; i++)
    {
        if (instances[i] != null)
        {
            instances[i].Dispose();
            instances[i] = null;
        }
    }
}

关于dispose的一件小事。

处理对象时,可以清除大型内容对象中的对象。您只需孤立正在处理的对象的内容,这样GC就可以自由地获取这些内容。

如果在要实现IDisposable的对象中没有任何大对象或数组,那么就不需要对其进行处理。如果您需要内存中的空间,那么只需将其置空,即可将其强制移出作用域并进入GC。

(这里有一个角落的例子,GC会停止你的程序来收集,所以如果你有很多小对象,那么在你有"时间"的时候处理它们是一个很好的方法,并且记得在处理它们之后抑制GC)

处置在某种程度上是一种判断,作为开发人员,你可以这样做。在大多数情况下,您并不真正需要它,在许多情况下,它很适合处理包含较大数组/集合的对象。

因此,对于您的问题,我建议您在完成类时进行处理,而不是等到"范围"结束,或者将它们放在列表中,稍后再进行处理。

Queue<IDisposable> toDispose = new Queue<IDisposable>();
private void DisposeObjects(){
    while(toDispose.Any()){
        toDispose.Dequeue()?.Dispose();
    }
}

MSDN:处置模式