Can I override Dispose to make an entity class tha

2019-04-11 18:28发布

问题:

This is a fairly fine point, and I expect the answer is "it's not a hot idea to begin with" - that said, it has a points that I'm interested in regardless, if someone is kind enough to indulge.

Model Code:

public partial class MyEntities : ObjectContext
{
    // the idea is if the object is in a using block, this always gets called?
    protected override void Dispose(bool disposing)
    {
        this.SaveChanges();
        base.Dispose(disposing);
    }
}

Client Code:

using(var model = new MyEntities())
{
   // do something

   // no worry about calling model.SaveChanges()
}

The issues I'm uncertain about are:

  1. Is Dispose the right place to do this because I was thinking "Finalize" for some reason - I always get confused on C# destruction.

  2. In the case an exception is thrown in the client code, ordinarily SaveChanges would be skipped and that's good, but if this works how I think, it'll always call it. Should I use try with an empty catch?

    public partial class MyEntities : ObjectContext
    {
        protected override void Dispose(bool disposing)
        {
            try
            {
               this.SaveChanges();
            }
            catch {}
            base.Dispose(disposing);
        }
    }
    

回答1:

Don't do this. It's a bad idea.

The purpose of "Dispose" is to politely dispose of an unmanaged resource early so that other processes can use it. "Dispose" should not have semantics -- it should not change the state of your program or be required in some way. It should only do precisely what it says it does: dispose of a resource.

Should you do it in the finalizer? Absolutely not. That's even worse. The finalizer might not run at all, the finalizer runs on another thread, the finalizer can be called even if the object wasn't properly initialized, and so on. Writing a finalizer is almost never the right thing to do, and if you do write a finalizer it should only dispose of a resource. Do not do anything fancy in a finalizer; you will almost certainly write a dangerously incorrect and brittle program if you do.

The right principle to cleave to here is: if a call is required for semantic reasons then force the user to put the call in the code. If they forget to do it, they'll find out in testing. Let the user decide whether it is the right thing to do to put the call in a finally block or not. Don't make that decision for them; you might decide wrong.



回答2:

  1. Dispose is where you would do this, if you were to do it at all.

  2. This is one of the reasons you should not do it.