摆脱嵌套的使用(...)语句

Gho*_*der 25 c# idisposable using

有时我需要在函数中使用几个一次性对象.最常见的情况是使用StreamReader和StreamWriter,但有时它甚至比这更多.

嵌套使用语句快速加起来并且看起来很难看.为了解决这个问题,我创建了一个小类,它收集IDisposable对象并在它本身被处置时处理它们.

public class MultiDispose : HashSet<IDisposable>, IDisposable
{
    public MultiDispose(params IDisposable[] objectsToDispose)
    {
        foreach (IDisposable d in objectsToDispose)
        {
            this.Add(d);
        }
    }

    public T Add<T>(T obj) where T : IDisposable
    {
        base.Add(obj);
        return obj;
    }

    public void DisposeObject(IDisposable obj)
    {
        obj.Dispose();
        base.Remove(obj);
    }


    #region IDisposable Members

    public void Dispose()
    {
        foreach (IDisposable d in this)
        {
            d.Dispose();
        }

    }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

所以我的代码现在看起来像这样:

        using (MultiDispose md = new MultiDispose())
        {
            StreamReader rdr = md.Add(new StreamReader(args[0]));
            StreamWriter wrt = md.Add(new StreamWriter(args[1]));
            WhateverElseNeedsDisposing w = md.Add(new WhateverElseNeedsDisposing());

            // code
        }
Run Code Online (Sandbox Code Playgroud)

这种方法有什么问题可以导致问题吗?我故意离开了从HashSet继承的Remove函数,以便该类更灵活.肯定滥用这个功能会导致物体没有被正确处理掉,但是在没有这个类的情况下还有很多其他方法可以在脚下射击.

Cha*_*ion 47

你可以这样做:

using (var a = new A())
using (var b = new B())
{
    /// ...
}
Run Code Online (Sandbox Code Playgroud)

  • 服从Stylecop(或FxCop)的每一个建议都有点像跟随GPS单元进入湖中.有时您需要使用您的判断(哪些软件无法执行.) (27认同)
  • @Stewart如果StyleCop不喜欢这个StyleCop是错误的. (10认同)
  • 党!这就是IntelliSense语言的自我学习对你的作用!我已经使用C#多年了,并没有想过以这种方式使用语句链接:( (2认同)

Jon*_*eet 20

关于一般原则的几点:

  • 你的代码明显是非惯用的C#.基本上你要求任何使用你的代码的人都采用一种不同寻常的风格,但收效甚微.
  • 正如其他人所指出的,你可以在using没有额外括号的情况下嵌套语句
  • 如果您发现自己在单个方法中使用了大量的语句,则可能需要考虑将其分解为更小的方法
  • 如果您有两个相同类型的变量,则可以使用单个using语句:

    using (Stream input = File.OpenRead("input.dat"),
           output = File.OpenWrite("output.dat"))
    {
    }
    
    Run Code Online (Sandbox Code Playgroud)

现在假设你真的想继续这样做:

  • 您的代码将以难以预测的顺序处理其包含的资源.它应该嵌入一个列表 - 而不是使用一个集合 - 然后按照与调用相反的顺序处理事物Add.
  • 没有理由获得来自HashSet<T>或任何集合.你应该类中有一个列表作为私有成员变量.
  • 如果其中一个Dispose呼叫失败,则不会进行任何其他Dispose呼叫; 使用传统using语句,每次调用Dispose都在自己的finally块内进行.

基本上,我认为这是一个坏主意.深度嵌套两层远非痛苦; 筑巢三应该是罕见的; 嵌套四个或更多强烈建议重构.你应该设计远离它,而不是试图应对深层筑巢的痛苦.


Chr*_*lor 13

也许只是你已经展示了一个简单的例子,但我认为以下内容更具可读性.

 using (StreamReader rdr = new StreamReader(args[0])) 
 using (StreamWriter wrt = new StreamWriter(args[1])) 
 {     
   // code 
 }
Run Code Online (Sandbox Code Playgroud)


SLa*_*aks 7

您可以using通过仅使用一对大括号使嵌套语句更漂亮,如下所示:

using (StreamReader rdr = new StreamReader(args[0])) 
using (StreamWriter wrt = new StreamWriter(args[1])) 
{
    ///...
}
Run Code Online (Sandbox Code Playgroud)

要回答你的问题,你需要按照相反的顺序处理.
因此,你不能使用HashSet.

此外,没有理由将IDisposables 列表暴露给外界.
因此,您不应该继承任何集合类,而是保持私有List<IDisposable>.

然后你应该有公共Add<T>Dispose方法(没有其他方法),并向后循环列表Dispose.