Detecting a Dispose() from an exception inside using block

前端 未结 8 503
暖寄归人
暖寄归人 2021-02-01 19:13

I have the following code in my application:

using (var database = new Database()) {
    var poll = // Some database query code.

    foreach (Question question          


        
相关标签:
8条回答
  • 2021-02-01 19:44

    In short: I think that's impossible, BUT

    What you can do is to set a flag on your Database class with default value "false" (it's not good to go) and on the last line inside using block you call a method that sets it to "true", then in the Dispose() method you may check whether the flag "has exception" or not.

    using (var db = new Database())
    {
        // Do stuff
    
        db.Commit(); // Just set the flag to "true" (it's good to go)
    }
    

    And the database class

    public class Database
    {
        // Your stuff
    
        private bool clean = false;
    
        public void Commit()
        {
            this.clean = true;
        }
    
        public void Dispose()
        {
            if (this.clean == true)
                CommitToDatabase();
            else
                Rollback();
        }
    }
    
    0 讨论(0)
  • 2021-02-01 19:48

    As Anthony points out above, the problem is a fault in your use of the using clause in this scenario. The IDisposable paradigm is meant to ensure that an object's resources are cleaned up regardless of the outcome of a scenario (thus why an exception, return, or other event that leaves the using block still triggers the Dispose method). But you've repurposed it to mean something different, to commit the transaction.

    My suggestion would be as others have stated and use the same paradigm as TransactionScope. The developer should have to explicitly call a Commit or similar method at the end of the transaction (before the using block closes) to explicitly say that the transaction is good and ready to be committed. Thus, if an exception causes execution to leave the using block, the Dispose method in this case can do a Rollback instead. This still fits in the paradigm, since doing a Rollback would be a way of "cleaning up" the Database object so that it is not left an invalid state.

    This shift in design would also make it much easier to do what you want to do, since you won't be fighting the design of .NET to try and "detect" an exception.

    0 讨论(0)
提交回复
热议问题