【问题标题】:How should I deal with null objects in a using block?我应该如何处理 using 块中的空对象?
【发布时间】:2011-09-22 12:55:55
【问题描述】:

鉴于这样的情况:

using (var foo = CreateFoo()) {
    if (foo != null) {
        // do stuff
    }
}

我想避免嵌套的 if。可悲的是,明显的解决方案是不可能的,因为 break 不适用于 using:

using (var foo = CreateFoo()) {
    if (foo == null) {
        break;
    }
    // do stuff
}

是否有一种模式仍然可以避免if != null 引起的额外缩进?

【问题讨论】:

  • 如果你的代码保持原样有什么问题吗?
  • @Boomer:不,没有。这是一个细节。

标签: c# .net using code-readability


【解决方案1】:

如果您对从 CreateFoo() 返回的类有足够的控制权,您可以只实现 Null Object 并返回它而不是实际的 NULL 值

【讨论】:

  • 这是个好主意。工厂方法使用空对象模式。
【解决方案2】:

我喜欢小的明确命名的方法:

public void DoWhatEver()
{
   using (var foo = CreateFoo())
   {
     if (foo == null) return;

     //DoWhatEver
   }
}

【讨论】:

    【解决方案3】:

    引入一个接受 lambda 的辅助方法。所以你的代码变成了:

    UsingIfNotNull(CreateFoo(), foo => {
      //do stuff
    });
    

    它有你想要的缩进。 UsingIfNotNull 的定义是:

    public static void UsingIfNotNull<T>(T item, Action<T> action) where T : class, IDisposable {
      if(item!=null) {
        using(item) {
          action(item);
        }
      }
    }
    

    【讨论】:

      【解决方案4】:

      这只是一个样式问题...代码很好。你真的那么担心缩进吗?无论如何,这是另一种丢失缩进的方法......

      public void DoWhatEver()
      {
         using(var foo = CreateFoo())
         {
             DoStuffWithFoo(foo);
         }
      
      }
      
      private void DoStuffWithFoo(Foo foo)
      {
          if(foo == null) return;
      
          //DoWhatEver
      
      }
      

      【讨论】:

        【解决方案5】:

        在一般意义上,我相信我会将 using 包装在 try...catch 块中,如果对象为 null,则抛出异常,但这是个人喜好。

        【讨论】:

        • 在这种情况下,我明确希望空对象静默失败。
        • 好吧,你可以抛出异常,捕捉它,然后什么都不做,尽管如果你想默默地失败,这可能不是你想要的;这会对资源产生影响,听起来空对象是一种预期的东西。话虽如此,也许您应该专注于不尝试实例化无法实例化的东西?
        • 是的,它也不会提高可读性,这是这个问题的重点:)
        • 遗憾的是,CreateFoo 方法不能保证成功,也没有办法改变它,如果它碰巧失败,它并不重要,必须被忽略。 (事实上​​,它只是试图打开一个可能被锁定的文件。)
        【解决方案6】:

        就我个人而言,我可能会保留您发布的代码。

        但是,既然您提出了要求(并且冒着让自己对这种经常被诽谤的语言功能投反对票的风险),您总是可以使用“goto”:

        using (var foo = CreateFoo()) {
            if (foo == null) {
                goto SkipUsingBlock;
            }
            // do stuff
        }
        
        SkipUsingBlock:
        // the rest of the code...
        

        【讨论】:

        • 作为 IT 的一年级学生,每次我们几乎不低声说“goto”时都会受到诅咒。当有可能看到“转到代码”时,它们已经遮住了我们的眼睛。
        【解决方案7】:

        这是一个丑陋的 hack,但它避免了额外的标识:

        do using (var foo = CreateFoo()) {
            if (foo == null) {
                break;
            }
            // do stuff
        } while (false);
        

        (不,我不建议这样做。这只是一个概念证明,表明它是可能的。)

        如果可能,我会建议重构您的代码:

         using (var foo = CreateFoo()) {
            if (foo != null) {
                doSomethingWith(foo);  // only one line highly indented
            }
        }
        

        【讨论】:

        • 来自 C 中的旧宏扩展 :) do {...} while (0);
        【解决方案8】:

        C# 编译器处理 using(var foo = CreateFoo()) 语句:

        try
        {
        var foo = CreateFoo();
        }
        finally
        {
          ((IDisposable) foo).Dispose();
        }
        

        如果您的方法 CreateFoo 返回的不是一次性对象 - 根本不要使用 using。在其他情况下,您可以编写:

        try
        {
        var foo = CreateFoo();
        //do stuff like foo.SomeMethod (if foo == null exception will be thrown and stuff will not be done)
        }
        finally
        {
          ((IDisposable) foo).Dispose();
        }
        

        【讨论】:

        • 这无济于事,因为仍然没有办法打破以避免缩进。
        • 另外,作为参考,描述似乎不准确:foo 应该包含在外部范围的新块中,最后有一个空检查。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-18
        • 1970-01-01
        • 1970-01-01
        • 2011-04-21
        • 1970-01-01
        相关资源
        最近更新 更多