【问题标题】:C# possible mistaken empty statementC# 可能错误的空语句
【发布时间】:2017-07-03 10:13:44
【问题描述】:

在 C# 中,我可以这样写:

using (new MyDisposableClass().MethodA());

分号会导致显示编译器警告,说明可能存在错误的空语句。上面的代码我没有运行,但是方法还是不会被调用?

这种编码约定有什么用处?我在这里看到了另一个关于这个的帖子,但我问一下,如果现在/因此有不同的回复有什么不同。

谢谢

【问题讨论】:

  • 你想用这个子句达到什么目的?
  • 使用的重点是该子句定义了变量,而正文是您使用所述变量执行某些操作的地方。如果您按照预期的方式使用该语句,则不会遇到此问题。
  • @unholysampler:不是variable,而是reference
  • 这里;有意使用,您可以使用#pragma 关闭此警告
  • @unholysampler 恕我直言,using 的意义在于它定义了您使用一次性资源的范围,然后自动处置它。您不必将其分配给变量,如 ASP.NET MVC 中所示 - using (Html.BeginForm()) { ... }(而不是显式调用 Html.EndForm()

标签: c#


【解决方案1】:

这段代码基本上翻译成

MyDisposableClass tmp = new MyDisposableClass().MethodA();
try
{
}
finally
{
    if( tmp != null )
        tmp.Dispose();
}

基本上,您将调用结果处理为MethodA,而不是处理可能的意图MyDisposableClass

using 语句后面的; 是合法的,但警告表明您可能错误地将其添加到那里。例如下面的代码不会编译:

using( var tmp = new MyDisposableClass() );
{
    tmp.MethodA();
}

解析器评估两个完全独立的块,编译器会看到,就好像你输入了这个:

using( var tmp = new MyDispoableClass() )
{

}


{
    tmp.MethodA();
}

很容易通过眼睛错过悬空的;,因此编译器警告只是暗示您可能打算做其他事情。有时需要更简洁的陈述,我认为表明它是故意的最好方法是使用{}而不是;

using( new MyDisposableClass().MethodA() ){}

请注意,这是处理 MethodA 调用的结果,而不是 MyDisposableClass 实例。你的代码实际上应该写成

using( var tmp = new MyDisposableClass() ){ tmp.MethodA(); }

【讨论】:

  • 这只是假设MethodA() 返回一个MyDisposableClass
  • @Daniel - 它不必是 MyDisposableClass - 只需 IDisposable。
  • 不,这:MyDisposableClass tmp = new MyDisposableClass().MethodA(); 将要求 MethodA 返回一个 MyDisposableClass
  • Ummm....这是对原始代码的翻译——不对类定义做任何假设。其余使用 var 只需要 IDisposable。
【解决方案2】:

using 语句可以用作子句的开头,在该子句的末尾处理实例化对象。换句话说:

using (var foo = new bar())
{
  SomeStatments();
} 
//foo is disposed

using (var foo = new bar())
  SomeStatments();
//foo is disposed

您的分号没有结束using 语句。它实际上是在using 语句之后结束一个空子句。这往往不是程序员的真正意图。因此,编译器会发出“可能错误的空语句”警告。

更新:假设您在问题中列出的代码是实际代码,那么您可能应该将 MethodA 转换为 static 方法,因为您显然没有强制执行约束或依赖任何班级成员。

【讨论】:

    【解决方案3】:

    为什么要聪明?

    这应该是等价的,未来的开发人员不必在谷歌上搜索更简短的语法可能意味着什么。

    //By the name of the example, I can assume that MyDisposableClass 
    //implements IDisposable
    using (MyDisposableClass something = new MyDisposableClass())
    {
       //Assuming the example code compiles, then the return value of MethodA
       //implemented IDisposable, too.
       using(something.MethodA())
       {
    
       };
    }
    

    如果您只需要在一次调用后处理某些内容,为什么不让 MethodA 清理需要清理的内容?

    【讨论】:

    • 你确定它是等价的吗? using 期望引用对象作为参数,但他传递了 MethodA 的结果@
    • 示例名称混淆了问题。看起来 MyDisposable 不会被释放,并且 MethodA() 的返回值将被释放。我会更新我的代码。
    【解决方案4】:

    我认为这样写会更清楚:

    using (var myDisposable = new MyDisposableClass())
    {
       myDisposable.MethodA();
    }
    

    按照您的方式,MethodA 的结果实际上会被视为IDisposable 实现。

    【讨论】:

    • 你知道这不是提问者的意图,因为......?
    • 我的假设是基于他正在实例化的类称为MyDisposableClass。可能是他想对 MethodA 的结果应用 using 语句,但我认为更大的问题是意图不明确。
    【解决方案5】:

    也许对这个样本有帮助:

    public static class Helper {
        public static void Using<T>( Action<T> action ) where T : IDisposable, new() {
            var obj = new T();
            action( obj );
        }
    }
    
    // ...
    Helper.Using<MyDisposableClass>( cls => cls.MethodA() );
    Helper.Using<OtherClass>( cls => {
        for( int i = 0; i < 5; i++ ) { cls.DoRandom(); }
    } );
    

    【讨论】:

      【解决方案6】:

      您可能很想使用这种风格。它确实调用了该方法。但它充其量只是一个成语,它更有可能使下一个读者——包括你,几个月后——感到困惑,而不是启迪。

      甚至替换“;”使用空块(消除编译器警告)可能会在以后读取时导致头疼 - 请记住,代码的读取比写入的频率更高。

      Paul Alexander 的回答是正确的,但我没有足够的声誉来评论它。

      我只是在对方法抛出异常的副作用感兴趣的情况下使用它:

      try {
          using (var _ = File.Open(logPath, FileMode.Open, FileAccess.Read)) { }
      } catch (Exception ex) { ... }
      

      File.Open 返回一个必须关闭或释放的 FileStream。但我真的不喜欢它。我最终命名了变量并在块中放置了一个明确的 Close 。我觉得以后会更容易理解。

      【讨论】:

        【解决方案7】:

        有时会生成编译器警告,然后在您继续输入时不会被清除。尝试构建解决方案,看看它是否会消失。

        另外,我不确定你指的是什么逗号。您是指行尾的分号吗?

        【讨论】:

          【解决方案8】:

          这个方法本质上会调用 MethodA() 然后永远不会使用它。 'Using' 仅在特定的 using 块内使用括号中的任何内容。然后它超出范围。所以:

          using (new MyDisposableClass().MethodA())
          {
              //Code that uses MethodA()
          }
          

          ...不应该给出那个错误,但是 MethodA() 在 using 块之外仍然无法访问。

          澄清:

          您仍然可以在程序的其他位置调用new MyDisposableClass().MethodA(),但在代码using (new MyDisposableClass().MethodA()) 中进行的特定调用将超出范围并且无法访问。

          【讨论】:

          • using 块用于指定您希望何时处置使用资源的项目。在 using 块中的代码执行后,在对象上调用 Dispose() 并且对象基本上超出了范围。如果您键入“using (a = new optionalObject()){}”,那么除了 using 块之外,您将无法在其他任何地方访问“a”。如果您声明它然后不使用它(即“使用(a = newdisposableObject());”),那么编译器将抛出该警告。也许我没有正确解释这一点,但我的想法是正确的。 -2 我认为是不必要的。
          • 这里是“使用”的解释:stackoverflow.com/questions/212198/…
          • 哦,现在我看到了我的错误。 'using (new MyDisposableClass().MethodA())' 会产生警告,因为没有设置要使用的对象。明白了。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-10
          • 1970-01-01
          • 2021-01-11
          • 2015-02-25
          • 2018-01-29
          • 2013-11-21
          相关资源
          最近更新 更多