Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it ok to fire events from Dispose()?

In my current project I'm using classes which implement the following ITransaction interface shown below. This is a generic interface for a transaction that can be undone. I also have a TransactionSet class which is used to attempt multiple Transactions or TransactionSets, and can ultimately be used to create a tree of transactions.

Some implementations of ITransaction keep temporary references to object instances or files it may use later if there is a call to Undo(). A successful transaction can later be confirmed after which Undo() is no longer allowed and there is thus also no longer a need for the temporary data. Currently I'm using Dispose() as my confirmation method to clean up any temporary resources.

However, now I'd like my transactions to also fire events to notify other classes of what has taken place. I do not want the events to fire unless the transaction is confirmed. Because I don't want to allow a transaction to fire events multiple times by being undone and then run again.

Since I'm using Dispose() to confirm a transaction is there anything wrong with also firing these events from it? Or would it be better to have a separate Confirm() method on my interface that fires the events in addition to Dispose() which cleans up the temporary data? I can't think of any case where I would want to confirm, but not dispose a transaction. Yet it's not entirely clear to me what I should and should not do within Dispose().

public enum TransactionStatus
{
    NotRun, // the Transaction has not been run, or has been undoed back to the original state
    Successful, ///the action has been run and was successful
    Error //there was an attempt to run the action but it failed
}

/// <summary>
/// Generic transaction interface
/// </summary>
public interface ITransaction
{
    TransactionStatus Status { get; }

    /// <summary>
    /// Attempts the transaction returns true if successful, false if failed.
    /// If failed it is expected that everything will be returned to the original state.
    /// Does nothing if status is already Successful
    /// </summary>
    /// <returns></returns>
    bool Go();

    /// <summary>
    /// Reverts the transaction
    /// Only does something if status is successful.
    /// Should return status to NotRun
    /// </summary>
    void Undo();

    /// <summary>
    /// A message describing the cause of the error if Status == Error
    /// Otherwise equal String.Empty
    /// </summary>
    string ErrorMessage { get; }
}
like image 952
Eric Anastas Avatar asked Jul 15 '10 04:07

Eric Anastas


People also ask

What is the use of Dispose ()?

The Dispose() method The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.

When Dispose is called in IDisposable?

Rule#1: Properly dispose of classes that implement IDisposable. The first rule is whenever you are consuming a class that implements the IDisposable interface; you should call the “Dispose” method when you are done with that class.

When the Dispose method is called?

It only occurs when there are objects in the Finalization Queue. It only occurs when a garbage collection occurs for Gen2 (which is approx 1 in every 100 collections for a well-written . NET app).


2 Answers

Dispose is not a special method - it's not like a ctor or a finalizer or anything - it's just a helpful pattern to notify an object the consumer is done using it. There's no reason it can't raise events.

like image 109
Rex M Avatar answered Sep 21 '22 17:09

Rex M


IDisposable is simply a runtime-integrated design pattern that facilitates object cleanup in a more efficient manner than finalization. There is very little you "can't" do in a disposal method, however you should be wary of doing some things.

While the IDisposable.Dispose() method is not a "real" destructor or finalizer, it can adversely affect the lifetime of an object if other objects maintain (or perhaps even take) a reference to the disposing object during disposal events. If you are careful about how you implement such a system, you can mitigate the possible side effects. However, it is important to realize the potential that such an implementation offers...such as increased attack surface for a malicious coder to exploit by, say, keeping your transaction objects alive indefinitely.

like image 27
jrista Avatar answered Sep 18 '22 17:09

jrista