Tek Eye Logo

Tek Eye

Managing Objects in C Sharp, a Life Cycle Template

Many computer programs developed today are designed around objects, or components, that are interlinked with methods and properties. A program, or application (app), can grow from having tens of objects to hundreds, and beyond. Managing these objects and ensuring the program remains efficient, correctly uses resources, and cleans up after itself is important. Having hundreds of objects can make that process painful. Once an app gets a little complex, it takes discipline to keep it well structured and easy to maintain. Many programs fall into the problem of spaghetti code as they develop. Today's agile development processes can accelerate the problem if the senior developers and managers take their eye of the ball.

In the past some software design patterns have been used to help organise the programs components, or programmers roll their own schemes. Here, at Tek Eye, simplicity is regarded as key. This article covers a staight forward way of managing objects in C#. Hopefully, if you are looking for an easy to understand and implement object management technique, you will find the object managing code here useful. In this article it is assumed Microsoft's Visual Studio is used, and a simple Windows Forms (WinForms) example is provided.

Visual Studio's Starting WinForms App

When a new Windows Forms Application, or WinForm app, is created in Visual Studio two files are created:

  • Program.cs - the main entry point, which sets up the app to run a user interface (UI) and then starts the first window, by running the first form.
  • Form1.cs - the first form for the program, started by Program.cs. In reality Form1.cs is the forms code, and there is a Form1.Designer.cs, containing the UI definition, and Form1.rex, containing any binary resources, e.g. icons or images.

Here is the initial Program.cs:

using System;
using System.Windows.Forms;

namespace Test
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

And the first form is empty:

A Basic WinForm

Encapsulating The Apps Functionality

The easist way to start writing the app's functionality is to drop some controls onto the form and add code behind the control's events. That's OK for simple apps, but for large programs logic is broken out into separate classes and grouped into Class Library projects (which are compiled into DLLs). A program can use many classes in many DLLs. These classes will be instantiated into the objects used in the program. What is an easy way to manage these C# objects? (Or VB objects.)

An Example Object

Here is a simple class. It can be added to a class project or into Program.cs:

class AClass
{
    public int SomeProperty { get; set; }
    public string SomeMethod()
    {
        return "I did Something.";
    }
}

We will assume that many classes will be produced to provide the app's functionality, therefore, we need a way to access all objects easily. The .NET List class provides a convenient way to manage a collection, that includes collections of objects. Add a List to the Program class, here it'll be called Objects (the Program.cs will need a using System.Collections.Generic;). Notice it is declared static as we only need one List to manage our programs objects:

static class Program
{
    static List<Object> Objects = new List<object>();
    .
    .
    .

Then in Main create our objects and add them to the list:

//Create a new object
AClass obj = new AClass();
//Add to the list of objects
Objects.Add(obj);

We can now create objects and access them via a list. Next, give the UI access to the objects.

Easily Accessing Objects from Forms.

Obviously, you can declare and use an object in a form. However, several forms may need to share the same object. Therefore, just pass the list of objects into each form. Start by adding a property to the form to store the reference to the list:

public partial class Form1 : Form
{
    public List<Object> ProgramObjects { get; set; }

    public Form1()
    {
        .
        .
        .

Now change the Program.cs to use this form's new property:

.
.
.
Form1 frm = new Form1();
frm.ProgramObjects = Objects;
Application.Run(frm);

Now access the object in the form (these examples uses Language INtegrated Query, LINQ, but the usual foraach way could be used). Note, a label and button has been dropped onto the form:

private void button1_Click(object sender, EventArgs e)
{
    AClass localClass =(AClass)ProgramObjects.Find(item => item.GetType() == typeof(AClass));
    if(localClass!=null)
        label1.Text=localClass.SomeMethod();
}

Obviously the local reference could be kept for reuse:

AClass localClass;
private void button1_Click(object sender, EventArgs e)
{
    if (localClass == null)
        localClass = (AClass)ProgramObjects.Find(item => item.GetType() == typeof(AClass));
    if (localClass != null)
        label1.Text = localClass.SomeMethod();
}

And you can allow for multiple versions of the same class being passed around in the objects list:

ProgramObjects.ForEach(item =>
{
    //Using the ?: operator for brevity instead of usual if else
    AClass aClass = item.GetType() == typeof(AClass) ? (AClass)item : null;
    if(aClass!=null)
        label1.Text = aClass.SomeMethod();
});

We now have a way of passing objects between forms, and between other objects, and accessing them via a List. The next thing to look at is cleaning up objects when finished with them.

Cleaning Up After Using Objects

When a form is finished with an object it may need to tell that object to save, or clean up, some data. Start by adding a CleanUp method to the object. It is virtual so derived classes can add there own clean up code by overriding CleanUp.

public virtual void CleanUp()
{
    //Perform clean up
}

This can then be called like any other method on the object:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    AClass localClass;
    localClass = (AClass)ProgramObjects.Find(item => item.GetType() == typeof(AClass));
    if (localClass != null)
        localClass.CleanUp();
}

Or if you kept the object reference in a forms module variable:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    if (localClass != null)
        localClass.CleanUp();
}

Programmers do not always remember ro perform clean up, or objects do not always end gracefully. That's when IDisposable is useful.

Deterministic Finalization with IDisposable

When using IDisposable use a common pattern, which Visual Studio can add automatically. The clean up method is now protected, it will be accessed via Dispose:

public class AClass : IDisposable
{
    public int SomeProperty { get; set; }
    public string SomeMethod()
    {
        return "I did Something.";
    }
    protected virtual void CleanUp()
    {
        //Perform cleanup;
    }
    #region IDisposable Support
    private bool disposedValue = false; // To detect redundant calls
    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                //Dispose managed state (managed objects).
                CleanUp();
            }
            // If unmanaged resources (unmanaged objects) are freed override a finalizer.
            // Set large fields to null.
            disposedValue = true;
        }
    }
    // This code added to correctly implement the disposable pattern.
    public void Dispose()
    {
        // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        Dispose(true);
        // Use GC.SuppressFinalize(this); if the finalizer is overridden.
    }
    #endregion
}

Then call Dispose to perform the cleanup

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    if (localClass != null)
        localClass.Dispose();
}

An when exiting the app entirely, all the objects can be cleaned up:

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    ProgramObjects.ForEach(item =>
    {
        IDisposable disposableaClass = item is IDisposable?(IDisposable)item:null;
        if (disposableaClass != null)
        {
            disposableaClass.Dispose();
        }   
    });
}

When using some types of resources, e.g. unmanaged resources, the finalizer is required, its been added in the following code. Plus lock has been added to make the Dispose thread safe:

#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
    //Make thread safe
    lock (this)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                //Dispose managed state (managed objects).
                CleanUp();
            }
            // Free unmanaged resources
            // Set large fields to null
            disposedValue = true;
        }
    }
}
//Finalizer
~AClass() {
    // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
    Dispose(false);
}
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
    // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
    Dispose(true);
    //With a finaliser prevent it happening twice
    GC.SuppressFinalize(this);
}
#endregion

Use a check to ensure objects don't run code once Dispose has executed, notice the use of lock for thread safety:

public string SomeMethod()
{
    if (Disposed)
        throw new ObjectDisposedException(this.GetType().Name);
    return "I did Something.";
}
protected bool Disposed
{
    get
    {
        //Make thread safe
        lock(this)
        {
            return disposedValue;
        }
    }
}

Of course, sub-classes implement their own clean up (change protected to public if not using IDisposable):

public class SubClass : AClass
{
    public void AnotherMethod()
    {
        //Do something else
    }
    protected override void CleanUp()
    {
        try
        {
            //Do sub-class clean up
        }
        finally
        {
            base.CleanUp();
        }
    }
}

The use of a single List to store references to objects, and using LINQ to access those objects, can make object management easier, especially cleaning up objects when they implement IDisposable. You could use a List to manage all UI forms, but other collections exist for forms. There is Application.OpenForms, plus for an MDI app, there is the MDIChildren array.

See Also

  • For a full list of the articles on Tek Eye see the website's index.

Author:  Published:  

ShareSubmit to TwitterSubmit to FacebookSubmit to Google+Submit to LinkedInSubmit to redditPrint Page

markdown CMS Small Logo Icon ↓markdown↓ CMS is fast and simple. Build websites quickly and publish easily. For beginner to expert.



Articles on:

Android Programming and Android Practice Projects, HTML, VPS, Computing, IT, Computer History, ↓markdown↓ CMS, C# Programming, Using Windows for Programming



Free Android Projects and Samples:

Android Examples, Android List Examples, Android UI Examples