c# - Should I Treat Entity Framework as an Unmanaged Resource? -
i working class uses reference ef in constructor.
i have implemented idisposable
, i'm not sure if need destructor because i'm not can classify ef unmanaged resource.
if ef managed resource, don't need destructor, think proper example:
public exampleclass : idisposable { public exampleclass(string connectionstringname, ilogger log) { //... db = new entities(connectionstringname); } private bool _isdisposed; public void dispose() { if (_isdisposed) return; db.dispose(); _isdisposed= true; } }
if ef unmanaged, i'll go this:
public exampleclass : idisposable { public exampleclass(string connectionstringname, ilogger log) { //... db = new entities(connectionstringname); } public void dispose() { dispose(true); } ~exampleclass() { dispose(false); } private bool _isdisposed; protected virtual void dispose(bool disposing) { if (_isdisposed) return; // dispose of managed resources if (disposing) { // dispose of managed resources; assumption here ef unmanaged. } // dispose of unmanaged resources db.dispose(); _isdisposed = true; //freed, no destructor necessary. gc.suppressfinalize(this); } }
which 1 it?
you never want use finalizer (destructor) in case.
whether dbcontext
contains unmanaged resources or not, , whether responsibly frees unmanaged resources or not, not relevant whether can try invoke dbcontext.dispose()
finalizer.
the fact that, time have managed object (which instance of dbcontext
is), never safe attempt invoke method on instance. reason that, time finalizer invoked, dbcontext
object may have been gc-collected , no longer exist. if happen, nullreferenceexception
when attempting call db.dispose()
. or, if you're lucky, , db
still "alive", exception can thrown within dbcontext.dispose()
method if has dependencies on other objects have since been finalized , collected.
as "dispose pattern" msdn article says:
x not access finalizable objects in finalizer code path, because there significant risk have been finalized.
for example, finalizable object has reference finalizable object b cannot reliably use b in a’s finalizer, or vice versa. finalizers called in random order (short of weak ordering guarantee critical finalization).
also, note following eric lippert's when know wrong, part two:
myth: finalizers run in predictable order
suppose have tree of objects, finalizable, , on finalizer queue. there no requirement whatsoever tree finalized root leaves, leaves root, or other order.
myth: object being finalized can safely access object.
this myth follows directly previous. if have tree of objects , finalizing root, children still alive — because root alive, because on finalization queue, , children have living reference — children may have been finalized, , in no particularly state have methods or data accessed.
something else consider: trying dispose? concern making sure database connections closed in timely fashion? if so, you'll interested in ef documentation has this:
by default, context manages connections database. context opens , closes connections needed. example, context opens connection execute query, , closes connection when result sets have been processed.
what means that, default, connections don't need dbcontext.dispose()
called closed in timely fashion. opened , closed (from connection pool) queries executed. so, though it's still idea make sure call dbcontext.dispose()
explicitly, it's useful know that, if don't or forget reason, default, not causing kind of connection leak.
and finally, 1 last thing may want keep in mind, code posted doesn't have finalizer, because instantiate dbcontext
inside constructor of class, possible dbcontext.dispose()
method won't called. it's aware of special case not caught pants down.
for instance, suppose adjust code ever allow exception thrown after line in constructor instantiates dbcontext
:
public exampleclass : idisposable { public exampleclass(string connectionstringname, ilogger log) { //... db = new entities(connectionstringname); // let's pretend have code can throw exception here. throw new exception("something went wrong after constructing db"); } private bool _isdisposed; public void dispose() { if (_isdisposed) return; db.dispose(); _isdisposed= true; } }
and let's class used this:
using (var example = new exampleclass("connstring", log)) { // ... }
even though appears safe , clean design, because exception thrown inside constructor of exampleclass
after new instance of dbcontext
has been created, exampleclass.dispose()
never invoked, , extension, dbcontext.dispose()
never invoked either on newly created instance.
you can read more unfortunate situation here.
to ensure dbcontext
's dispose()
method invoked, no matter happens inside exampleclass
constructor, have modify exampleclass
class this:
public exampleclass : idisposable { public exampleclass(string connectionstringname, ilogger log) { bool ok = false; try { //... db = new entities(connectionstringname); // let's pretend have code can throw exception here. throw new exception("something went wrong after constructing db"); ok = true; } { if (!ok) { if (db != null) { db.dispose(); } } } } private bool _isdisposed; public void dispose() { if (_isdisposed) return; db.dispose(); _isdisposed= true; } }
but above concern if constructor doing more creating instance of dbcontext
.
Comments
Post a Comment