Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Monitoring Attribute Value Changes inside a Class

0.00/5 (No votes)
7 Jan 2012 1  
A class that allows you to monitor the actual change of a variable and notifies all interested objects with an event

Introduction

Consider the case when there's a need to monitor the change of a class attribute. Each time the change occurs, an event should be raised to notify all interested objects. For this, I have developed a simple class which I often use.

Here's an example of such a need: we have a class, working with a database, which often executes queries. And we need monitoring the database channel state - whether it's OK or not.

Background

To achieve this, each time we have a successful query, we see if the connection is OK, and when the query fails because of the database connection - the channel state becomes disconnected.

We then have something like this:

public class DBGateway
{
    private bool connectionIsOk = false;

    public bool ConnectionIsOK 
    {
        get { return connectionIsOk; }
        private set 
        {
                        connectionIsOk = value;
            if (connectionIsOk == false && value == true)
                RaiseConnectionRestored();
            if (connectionIsOk == true && value == false)
                RaiseConnectionLost();
        }
    }

    private string connectionString;

    public void ExecuteQuery()
    {
        try
        {
            //...some useful staff: connection to database, and so on
            ConnectionIsOK  = true;  //because we are here, 
                                     //and no exception occured - then it's OK
        }
        catch(SqlException)
        {
            ConnectionIsOK = false;
            throw;
        }
    }

    private void RaiseConnectionRestored()
    {
        if (ConnectionRestored != null) ConnectionRestored(this, EventArgs.Empty);
    }    

    private void RaiseConnectionLost()
    {
        if (ConnectionLost!= null) ConnectionLost(this, EventArgs.Empty);
    }

    public event EventHandler ConnectionRestored;
    
    public event EventHandler ConnectionLost;
}

The wrong thing about this code is that the database gateway class has an additional responsibility. We've got two events, functions for raising these events, and the logic for checking whether the value really changed.

The ValueMonitor<T> Class

ValueMonitor is a simple class which encapsulates the logic of change checks. It has a ValueChanged event, a Value property, and a constructor which allows you to set the initial value of the monitored variable.

We need to pay special attention to value and reference types. The Equals function returns what is really expected for the value types.

However, the result of equality comparison for reference types is the result of "pointers" comparison. Not what we actually need. That's why for reference types IEqualityComparer is expected in the overloaded constructor version.

ValueMonitorDescription/ClassDiagram.png

Consider the value change check code:

public class ValueMonitor<ValueType>:IValueMonitor<ValueType>
{
    private ValueType aValue = default(ValueType);
    private IEqualityComparer<ValueType> comparer = null;

    //all other members are ommited ...    

    public ValueType Value
    {
        get { return aValue; }
        set
        {
            bool areEqual = false;
            if (comparer == null)
                areEqual = (aValue.Equals(value));
            else areEqual = comparer.Equals(aValue, value);

            if (areEqual == true) return;
                ValueType oldValue = aValue; // remember previous for the event rising
            aValue = value;
            if (ValueChanged != null)
                ValueChanged(oldValue, aValue);
        }
    }
}

Using the Code

Now the code for our DBGateway class will look like this:

public class DBGateway
{
    private ValueMonitor<bool> connectionIsOk = new ValueMonitor<bool>(false);

    public IValueMonitor<bool> ConnectionIsOK 
    {
        get { return connectionIsOk; }
    }

    private string connectionString;

    public void ExecuteQuery()
    {
        try
        {
            //...some useful staff: connection to database, and so on
            connectionIsOk.Value  = true; //because we a here, 
                                          //and no exception occured - then it's OK
        }
        catch(SqlException)
        {
            connectionIsOk.Value = false;
            throw;
        }
    }
}

As you see, we got rid of additional logic, and our class became lighter, and we now can concentrate on the DB code rather than the value change monitoring.

Example Application

Of course, in the example code, we don't monitor the database connection. To see the working of the class, the user sets values true and false to the status variable inside the Form class.

The form handles the ValueChanged event and shows the time of actual change of the variable.

ValueMonitorDescription/lastUpdated.gif

Clicking the same button several times gives no effect. Changing the button does.

Points of interest

Usage examples:

  • Monitoring state of any kind of channel like in the DBGateway example.
  • Monitoring the change of state of an object. Imagine we have an implementation of the State pattern and we want to be aware of the current state and its change. Then we have an enumeration like this:
    public enum ObjectState
    {
       Disconnected,
       LoggingIn,
       Normal
    }

    Then, to provide value change monitoring, we add something like:

    ValueMonitor<ObjectState> currentState = 
             new ValueMonitor<ObjectState>(ObjectState.Disconnected);
  • The case when you receive the traffic from another client application and you'd like to monitor the IP address of the currently connected one. The situation is not so rare: two hosts may use different channels, and when one fails, the other (backup host) connects and the system is still stable.

History

  • 7.01.2012 - First version
  • 8.01.2012 - After Ravi Bhavnani's remark, the first example of DBGateway was changed. The line:
    connectionIsOk = true;

    was added into the ConnectionIsOK property.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here