Jun 08 2010

Initialization State Manager

Often you need to run some initialization operations during application startup or control creation. Assume you can’t show or enable UI till all operations complete. In this case you need some code to watch for server requests and raise some ‘InitializationCompleted’ event when all requests are done.

This piece of code should store and manage current state (which operations are in Running state and which one are completed) somehow. And it is better if state management code will be reusable.

This is exactly what I gonna  to build for you.

I’d like the idea to use enum to define initialization phases:

[Flags]
public enum InitializationPhases: uint
{
	None = 0,
	MachineSeetingsLoad = 1,
	UserSettingsLoad = 2
}

Please note that I use Flags attribute on the enum type. This allow us to use bitwise operations on enum values.

The idea is to set particular bit to ‘1’ when operation starts and mark as ‘0’ when operation completes. If all bits become ‘0’ then all operations will be completed.

To make code reusable I’d like to create generic type. Unfortunately we can’t  define enum constraint for generic type parameter. But enum is also a structure so at least we could constraint generic parameter to structures.

Enum type support IConvertable interface. Which allow us to perform conversion to uint value and then we could do bitwise operations with that value. The only moment we should be sure about is that generic type is created with enum generic parameter. To check it we will use .NET  reflection.

public class InitializationStateManager<T> : INotifyPropertyChanged
    where T : struct, IConvertible
{
    private UInt32 _initializationPhasesInRun;

    static InitializationStateManager()
    {
        Type t = typeof(T);

        if (!t.IsEnum) throw new ArgumentException("T must be an enumerable type");

        bool flagsAttributeFound = false;
        foreach (object attribute in t.GetCustomAttributes(false))
        {
            flagsAttributeFound = attribute is FlagsAttribute;
            if (flagsAttributeFound) break;
        }
        if (!flagsAttributeFound) throw new ArgumentException("T must be marked with Flags attribute");
    }

    public bool IsInitialized
    {
        get { return _initializationPhasesInRun == 0; }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    protected void OnPropertyChaneged(String propertyName)
    {
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public void MarkPhaseCompleted(T phase)
    {
        _initializationPhasesInRun &= ~phase.ToUInt32(null);
        OnPropertyChaneged("IsInitialized");
    }

    public void MarkPhaseStarted(T phase)
    {
        _initializationPhasesInRun |= phase.ToUInt32(null);
    }
}

In constructor we check what generic type parameter is enum and marked with Flags attribute.

Two methods MarkPhaseStarted and MarkPhaseCompleted are used to indicate that initialization phase started or completed. When all initialization phases will be completed the PropertyChanged event will be raised.

There are still some missed functionality:

  1. Code is not thread safe
  2. Probably it should be a Start() method to indicate that all initialization phases are started, to avoid the situation when some phase will complete before other one start