Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way for a class that implements IDisposable to throw an exception if it's not been instantiated via a using block?

Tags:

c#

idisposable

I spotted some potentially dangerous classes that would be much less dangerous if they couldn't be instantiated unless they were done so within a using statement.

I'm wondering if there's a way to force the classes to only be instantiated in that way.

(I'm aware what the IL compiles out as which is why I'm not massively sure this is even possible)

Cheers,

Phil.

like image 383
Phil Winstanley Avatar asked Mar 31 '11 17:03

Phil Winstanley


4 Answers

There's no way to enforce it, but you can probably build a custom Code Analysis rule to flag it.

like image 63
CodeNaked Avatar answered Nov 14 '22 05:11

CodeNaked


No, there is no way to have the compiler enforce this. It would be dangerous to do so, in any case, as there are times you want to use IDisposable classes in other fashions, such as encapsulating them within a second IDisposable class impelementation, etc.

If your class is implemented properly, then the destructor should clean up any unmanaged, undisposed resources. This is less than ideal, but still can work.

One good option is to have the destructor raise an exception or log during debug. This can help you track, during testing and debug time, any "missed" cases of using an IDisposable improperly.

like image 41
Reed Copsey Avatar answered Nov 14 '22 07:11

Reed Copsey


For all effective purposes it is impossible. Especially since it doesn't have to be a using, someone could have written out the try{}finally{}. You could make sure anything unmanaged was properly disposed of in the finalizer.

like image 5
Yuriy Faktorovich Avatar answered Nov 14 '22 07:11

Yuriy Faktorovich


Doing this would make your object only usable within local scope. That means you couldn't safely store it in a class field, for example.

Although you can't force the client to write the using statement, you can encapsulate the resource in a method that does use the using statement. This would be your resource code:

public sealed class Resource : IDisposable {
  private Resource() { }
  public void Dispose() { ... }
  public void Use(Action<Resource> action) {
    using (var resource = new Resource()) {
      action(resource);
    }
  }
}

Now, client code is forced to use the Resource through its Use method:

Resource.Use(resource => { 
  // use the resource...
});
like image 3
Jordão Avatar answered Nov 14 '22 07:11

Jordão