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())
的特定调用将超出范围并且不可访问。