Schrödinger's box: Implementing delayed class type selection via Interfaces in .NET

Some geek speak here. This are really the notes for a more complete article, but it might help some folks out so I want to put it up before I forget what I learned when I go to sleep!

The Problem

In a Asp.Net development project I need to be able to call the methods and properties of an object in order to extract data from it. The problem is that I will not know until runtime which of several competing implementations I might need to call. It will depend on a number of factors.

How then can I make calls to an object without knowing what object type it is in advance? The solution in this case is what .Net calls “interfaces”.

Go ahead, read more.

ed note: I code in C#, but these features are available under VB.net.

Problem Scenario

We are going to re-implement Schrödinger’s box. Basically, we will write some code that can query something about whether it is alive or dead without knowing in advance what type of animal it is.

Basically what we want to be able to do is only care that whatever type of object we have, it will implement the bare minimum of what we need to do the experiment.  It needs to do two things…

  • Tell us what type of animal it is
  • Remember whether it is alive or dead

The Interface

So, no matter what type of animal we have it has to be a valid one for the test. We will tell this to C# by creating a interface definition in the App_Code folder. It seems to be tradtional to start interface definitions with a capital “I”. Here is that file (you can call it anything, but I picked “ItestAnimal.cs”).

public interface ItestAnimal
{
    bool isAlive { get; set; }
    string whatType { get; }
}

As you can see, this file implements nothing. Ever object that wants to be a ItestAnimal needs to implement that functionality itself. BTW = those weird definitions are tied to the .NET 2.0 way to declare class properties.

The Animal Classes and Interface Declaration

We have two of them, “Dog” and “Cat” (Dog.cs and Cat.cs of course). I will show you only Dog here but Cat is the same thing, just do a search/replace of “Dog” with “Cat”. You may also want to check the constructor comment and change that.

It is important to understand that these classes do not have to have anything in common at all though these do for simplicity. The can also implement the interface required functions in totally different ways. It won’t change anything – that is the whole point.

All the magic happens at the class declaration where the “:” indicates that this class implements a particular interface. You can implement a bunch of them, just use a comma to separate them.

public class Dog : ItestAnimal
{
    private bool alive;

    public bool isAlive
    {
        get
        {
            return alive;
        }

        set
        {
            alive = value;
        }
    }

    public string whatType
    {
        get
        {
            return "Dog";
        }
    }

	public Dog()
	{
		//
		// Woof!
		//
	}
}

Simple Usage Example

I am not going to try and implement the whole thing here. You can do that for fun. What I will show you is that it doesn’t make any difference which animal you use, so you can delay the choice till runtime.

        // this section was created for the blog post,
        // it may have a typo but you get the idea
        //
        ItestAnimal animal_1;
        ItestAnimal animal_2;
        string animal_1_type;
        string animal_2_type;

        animal_1 = new Dog();
        animal_2 = new Cat();

        animal_1.isAlive = true;
        animal_2.isAlive = false;

        animal_1_type = animal_1.whatType;
        animal_2_type = animal_2.whatType;

Notice that we do not need to know or care what type of object something is as long as we only want to work with the properties and methods of the interface.

Schrödinger’s box

Here’s what you do to prepare the test page or form:

  • Set up a dropdown list called “animalList”. Give it two items, “Dog” and “Cat”.
  • Set up a checkbox named “statusFlag”.
  • Set up a text label, call it “peek”.
  • Set up a button and call it “doPeek”

Once all that is done, here is the callback for the button or link…

    protected void doPeek_Click(object sender, EventArgs e)
    {
        ItestAnimal thethinginthebox;

        switch (animalList.Text)
        {
            case "Cat":
                thethinginthebox = new Cat();
                thethinginthebox.isAlive = statusFlag.Checked;
                break;
            case "Dog":
                thethinginthebox = new Dog();
                thethinginthebox.isAlive = statusFlag.Checked;
                break;
            default:
                // I like dogs better
                thethinginthebox = new Dog();
                thethinginthebox.isAlive = statusFlag.Checked;
                break;
        }

        if (thethinginthebox.isAlive)
        {
            peek.Text = thethinginthebox.whatType + " is Alive!!!!";
        }
        else
        {
            peek.Text = thethinginthebox.whatType + " is Dead!!!!";
        }
    }

Enjoy!

References