4

There is a class library used by some application. It contains a class A for external usage with a static field of another private class B inside the library. User application uses instances of class A from the library.

As the application shutdowns I'd like to perform some clean up in class B. Is it possible to catch application shutdown event in class B without any action from user application?

class B
{
    public B()
    {
        // attach Handler() to applicaiton shutdown event
    }

    void Handler()
    {
        // do some work
    }
}
skaffman
  • 398,947
  • 96
  • 818
  • 769
Chesnokov Yuriy
  • 1,760
  • 5
  • 21
  • 35

2 Answers2

7
using System.Windows.Forms;

public class B
{
    public B()
    {
        Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
    }

    void Application_ApplicationExit(object sender, EventArgs e)
    {
        //do cleanup of your class
    }
}
4

If I understand this correctly, your model looks like this:

Initial scenario

You would then like to have ClassB communicate with Application through ClassA like shown below:

Goal

From an object-oriented design standpoint, this violates the Law of Demeter, which states that objects should only talk to their direct neighbors. In this regard I would suggest you to do the cleanup in ClassA, if possible.

From an implementation point of view, I would let ClassA explicitly state its dependency on Application by taking an instance of it in the constructor. This way you could easily subscribe to any events published by Application inside ClassA or, potentially, ClassB since inner classes in C# can access the outer class' private members:

public class A
{
    private readonly Application application;

    public A(Application application)
    {
        if (application == null)
        {
            throw new ArgumentNullException("application");
        }

        this.application = application;
        this.application.ApplicationExit += application_ApplicationExit;
    }

    private void application_ApplicationExit(object sender, EventArgs e)
    {
        // Perform cleanup
    }
}
Enrico Campidoglio
  • 56,676
  • 12
  • 126
  • 154
  • No, the interaction path is app->A->B There are no backward paths, class B runs on its own and fetches some data from db in a thread and synch it with its mem. Class A query B for the db kept in its mem – Chesnokov Yuriy Aug 03 '11 at 09:33
  • App have interface object of A implementation, which is repository with only one function to FindAll(), and I needed app shutdown event in B to synchronize mem with db – Chesnokov Yuriy Aug 03 '11 at 09:35
  • @Chesnokov Yuriy Subscribing to an event published by another class creates a strong association between the subscriber and the publisher. In this sense, if `ClassB` subscribes to an event published by `Application` then objects of `ClassB` have a strong dependency on the `Application` object. I still think that this kind of associations should be *made explicit in the design* to raise awareness of any possible side effects that could result from changes. – Enrico Campidoglio Aug 03 '11 at 09:55
  • I see, then destructor ~B() is the right place to catch it, since B is declared as static field in A and will be called only once. I tried that but as destructor is called the logger disposed of its observers and log message is not saved. I need to debug the issue further – Chesnokov Yuriy Aug 03 '11 at 10:54
  • ~B() is called after program flow return from Program.Main() where all logging is finalized and it is not possible to save results of ~B() to log – Chesnokov Yuriy Aug 03 '11 at 11:14