C#可能错误的空声明

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

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

分号会导致显示编译器警告,指出可能出错的空语句。 我没有运行上面的代码,但仍然不会调用该方法?

这种类型的编码约定有什么用处? 我在这里看到了另一个关于此问题的线索,但我要求现在存在差异/因此不同的回复。

谢谢

这段代码基本上转化为

 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(); } 

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

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

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

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

using语句可以用作子句的开头,在最后处理即时对象。 换一种说法:

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

要么

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

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

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

为什么要设法聪明?

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

 //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 (var myDisposable = new MyDisposableClass()) { myDisposable.MethodA(); } 

你拥有它的方式, MethodA的结果实际上将被视为IDisposable实现。

也许有助于这个样本:

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

你可能很想使用这种风格。 它确实调用了该方法。 但这充其量只是一个成语,并且更有可能让下一位读者 – 包括你,在几个月内 – 迷惑它而不是启发。

甚至取代“;” 使用空块(消除了编译器警告)可能会在以后读取时导致头部划伤 – 并且请记住代码的读取频率高于写入代码。

保罗亚历山大的答案是正确的,但我没有足够的声誉来评论它。

我在一个场合使用它,我只是对从方法抛出的exception的副作用感兴趣:

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

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

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

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

这个方法基本上会调用MethodA(),然后永远不会使用它。 ‘使用’仅使用括号中的任何内容使用块。 然后它超出了范围。 所以:

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

…不应该给出该错误,但在使用块之外仍然无法访问MethodA()。

澄清:

你仍然可以在程序的其他地方调用new MyDisposableClass().MethodA() ,但是using (new MyDisposableClass().MethodA())在代码中using (new MyDisposableClass().MethodA())的特定调用将超出范围并且不可访问。