GurdeepS
GurdeepS

Reputation: 67243

C# possible mistaken empty statement

In C#, I can write something like:

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

The semicolon causes a compiler warning to be shown which states possible mistaken empty statement. I haven't run the above code but won't the method still be called?

What uses is there of this type of coding convention? I saw another thread on here about this but I ask in case there areny differences now/therefore different replies.

Thanks

Upvotes: 4

Views: 4545

Answers (8)

davidbak
davidbak

Reputation: 6029

You may be tempted to use this style. It does call the method. But it is an idiom at best, and is more likely to confuse the next reader - including you, in several months - than it is to enlighten.

Even replacing the ";" with an empty block (which eliminates the compiler warning) might lead to head-scratching when read later - and remember that code is read more often than it is written.

Paul Alexander's answer is correct, but I don't have sufficient reputation to comment on it.

I have used it on an occasion where I was just interested in the side effect of an exception being thrown from the method:

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

File.Open returns a FileStream which must be closed or disposed. But I didn't really like it. I ended up naming the variable and putting an explicit Close in the block. I felt it would be easier to understand, later.

Upvotes: 0

MatthewMartin
MatthewMartin

Reputation: 33173

Why try to be clever?

This should be equivallent and future developers won't have to google what the briefer syntax might mean.

//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())
   {

   };
}

And if you need to dispose of something after only one call, why not make MethodA do the clean up of what ever needs to be cleaned up?

Upvotes: 2

TcKs
TcKs

Reputation: 26632

Maybe helps this sample:

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

Upvotes: 0

Abtin Forouzandeh
Abtin Forouzandeh

Reputation: 5855

The using statement can be used as the opening for a clause, at the end which an instantied object is disposed of. In other words:

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

or

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

Your semicolon isn't ending the using statement. It's actually ending an empty clause following the using statement. This is often not the programmers true intent. Thus, the compiler issues a "possibly mistaken empty statement" warning.

Update: Assuming the code you listed in the question is actual code, then you should probably turn MethodA into a static method, since you obviously are not enforcing a constraint or relying on any class members.

Upvotes: 3

Paul Alexander
Paul Alexander

Reputation: 32377

this code basically translates to

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

Basically you're disposing the result of the call to MethodA, rather than disposing of the MyDisposableClass which is the likely intent.

The ; following the using statement is legal but the warning suggests that you might have added it there by mistake. For example the following code won't compile:

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

The parser evaluates two entirely separate blocks and is seen by the compiler as if you had typed this:

using( var tmp = new MyDispoableClass() )
{

}


{
    tmp.MethodA();
}

It's easy to miss a dangling ; by eye so the compiler warning is simply suggesting that you probably meant to do something else. There are times when the shorter concise statement is desired and I think the best way to indicate that it is on purpose is to use {} instead of a ;.

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

Note still that this is disposing the result of the call to MethodA - not the MyDisposableClass instance. Your code should actually be written as

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

Upvotes: 11

Daniel Schaffer
Daniel Schaffer

Reputation: 57872

I think it would be clearer to write this:

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

The way you have it, the result of MethodA would actually be getting treated as the IDisposable implementation.

Upvotes: 1

Mike Webb
Mike Webb

Reputation: 9003

This method will essentially call MethodA() and then never use it. 'Using' uses whatever is in the parentheses only within that specific using block. Then it goes out of scope. So:

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

...should not give that error, but MethodA() will still be inaccessible outside the using block.

Clarification:

You can still call new MyDisposableClass().MethodA() elsewhere in the program, but the specific call made within the code using (new MyDisposableClass().MethodA()) will go out of scope and be inaccessible.

Upvotes: -2

dlras2
dlras2

Reputation: 8496

Sometimes compiler warnings are generated, then not cleaned up when you keep typing. Try building the solution, and see if it goes away.

Also, I'm not sure what comma you're referring to. Do you mean the semi-colon at the end of the line?

Upvotes: -1

Related Questions