Is “Using{}” good practice to dispose object even

2019-07-18 22:13发布

问题:

In my company, I am seeing code like this

using (LoggerFactory.GetTracer(_log.ModuleName + "._GetAccessTokenFromWns"))
{...}

When I looked up, I learned it disposes the objects referred by variables declared inside "Using" parenthesis.

Does it also help for code like above, where there is no variable referring to the object returned by the factory?

Thanks,

回答1:

After I see your question I write a simple code like this:

using (new FileStream("sample.txt",FileMode.CreateNew))
{

}

And then I look at the produced IL code:

    .method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       35 (0x23)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.IO.FileStream CS$3$0000,
           [1] bool CS$4$0001)
  IL_0000:  nop
  IL_0001:  ldstr      "asdas.txt"
  IL_0006:  ldc.i4.1
  IL_0007:  newobj     instance void [mscorlib]System.IO.FileStream::.ctor(string,
                                                                           valuetype [mscorlib]System.IO.FileMode)
  IL_000c:  stloc.0
  .try
  {
    IL_000d:  nop
    IL_000e:  nop
    IL_000f:  leave.s    IL_0021
  }  // end .try
  finally
  {
    IL_0011:  ldloc.0
    IL_0012:  ldnull
    IL_0013:  ceq
    IL_0015:  stloc.1
    IL_0016:  ldloc.1
    IL_0017:  brtrue.s   IL_0020
    IL_0019:  ldloc.0
    IL_001a:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_001f:  nop
    IL_0020:  endfinally
  }  // end handler
  IL_0021:  nop
  IL_0022:  ret
} // end of method Program::Main

As you can see it is still calling the Dispose method.It creates FileStream instance before try block, then calling the Dispose method in the finally.I think this is another advantage of using statements.



回答2:

"Disposal" of an object involves cleaning up any resources it may have initialized for its own use. The important task isn't cleaning up a reference, it is clearing file locks, mutexes, etc.



回答3:

This is the only way of ensuring the disposal of an object without introducing a variable for it. This is the same as

var __invisible = LoggerFactory.GetTracer(_log.ModuleName + "._GetAccessTokenFromWns");
try {
} finally {
    __invisible.Dispose();
}

but without the __invisible variable.

This construct is especially valuable in situations when you do not need a variable, because readers who are familiar with this idiom will find such code more readable.



回答4:

I believe it still has the same effect. If GetTracer is returning an instance of a class which implements IDisposable then this code is ensuring that instance is properly disposed of. Just because there is no assignment of the return value doesn't mean a resource which requires disposal wasn't allocated. The tracer for example could be opening a file and without the using statement that file lock/ streamreader or whatever resource my go indisposed.