BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

System Information
.NET 1.1+

Detecting Environment Shutdown

When an application domain starts to unload or the CLR begins to shut down, certain actions can no longer be performed safely. It is important to be able to detect these conditions in order to finalize objects correctly.

Environment.HasShutdownStarted

If you create a class with a finalizer, sometimes known as a destructor, it is important that you correctly detect when the .NET environment is shutting down. This can happen because your program is closing and the application domain is unloading, or because the common language runtime (CLR) is being shut down. If you do not detect this state, you might try to access static variables of the class, which may not be available if they have already been finalized.

Handily, the Environment class includes a simple Boolean property that you can check before attemping to use members that may no longer be available. HasShutdownStarted returns true if a shutdown process is in progress and false otherwise.

We can demonstrate with a simple program. Create a console application and add a new class file named, "MyItem". Objects of this type will hold a name in a string property. The finalizer shows a message if the application domain is unloading or the CLR is shutting down.

class MyItem
{
    public MyItem(string name)
    {
        Name = name;
    }

    public string Name { get; private set; }

    ~MyItem()
    {
        if (Environment.HasShutdownStarted)
        {
            Console.WriteLine("Removed {0}", Name);
        }
    }
}

Modify the Program class to contain the code below. This allows you to add instances of the MyItem class to a list and later manually remove them using basic text commands. When the program exits, any items still in the list will be finalized, showing the removal message.

NB: Although the Environment.HasShutdownStarted property is available from .NET version 1.1, this example requires .NET 3.5 in order to use lambda expressions, automatically implemented properties and implicitly typed variables.

class Program
{
    static List<MyItem> _items;
        
    static void Main(string[] args)
    {
        string input = null;
        _items = new List<MyItem>();
        Console.ForegroundColor = ConsoleColor.White;

        while (input != "exit")
        {
            Console.Write(">");
            input = Console.ReadLine().Trim();
            ProcessInput(input);
        }
    }

    static void ProcessInput(string input)
    {
        if (input.StartsWith("add ", StringComparison.InvariantCultureIgnoreCase))
        {
            AddFromInput(input);
        }
        else if (input.StartsWith("remove ", StringComparison.InvariantCultureIgnoreCase))
        {
            RemoveFromInput(input);
        }
        else if (string.Compare("exit", input,
                                StringComparison.InvariantCultureIgnoreCase) != 0)
        {
            ShowError("Unknown command");
        }
    }

    static void AddFromInput(string input)
    {
        _items.Add(new MyItem(input.Substring(4)));
        ShowItems();
    }

    static void RemoveFromInput(string input)
    {
        var name = input.Substring(7);
        var toRemove = _items.FirstOrDefault(
            i => string.Compare(i.Name, name,
                                StringComparison.InvariantCultureIgnoreCase) == 0);

        if (toRemove != null)
        {
            _items.Remove(toRemove);
        }
        else
        {
            ShowError("Item not found");
        }

        ShowItems();
    }

    static void ShowItems()
    {
        Console.ForegroundColor = ConsoleColor.Gray;
        foreach (var item in _items)
        {
            Console.WriteLine(item.Name);
        }
        Console.ForegroundColor = ConsoleColor.White;
    }

    static void ShowError(string error)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine(error);
    }
}

Try running the program. To add items to the list, enter "Add ", followed by a name. Remove items with "Remove " and the name. When you remove an item manually, the message from the finalizer is not shown. Enter "Exit" to close the program. Any items remaining in the list will be finalized and their messages shown.

NB: If you run the program from within Visual Studio, launch it by pressing Ctrl-F5 so that the console does not close automatically.

12 December 2015