Author - Dave Amour

Dave Amour has used computers for as long as he can remember and intially started out as an IT trainer delivering a range of IT courses but for the last 11 years has been focusing on the arena of web application development. He was worked for numerous companies over the years and is currently working for Audacs Software Ltd. Dave is also a keen squash player and an active and sucessful member of Experts Exchange

Please feel free to submit any constructive comments which you can do at the bottom of this page.

Dave may be available for programming tuition or consultancy work. Contact via dave@audacs.co.uk
Dave Amour - Click to view CV 

Sealed Classes and Extension Methods

Have you ever been working with someone elses code and needed to add functionality to a class but the code author has unkindly created their class as sealed?

Not nice eh?  I have seen colleagues working with such controls in asp.net and hooking into the rendered html and modifying that just in time with string manipulation!

Thers is a neater way of extending such sealed classes and under the hood its all smoke and mirrors but it looks good and works well and that's all that matters.

What I am talking about is Extension methods.

Extension methods allow you to seemingly add new methods to existing classes so lets look at some examples and see how this works.

Consider the following class:

    public sealed class Person
    {
        public void PayTaxes()
        {
            Console.WriteLine("I am paying my taxes");
        }
 
        public void Eat()
        {
            Console.WriteLine("Munch munch");
        }
    }


This class is sealed but suppose we wanted to give our person some musical abilities and enable him to play the piano.

Well normally we might create a sub class called PianoPlayer which inherited Person and simply added a PlayPiano method or two.  Not possible when the class is sealed though.  Therefore there is some trickery built into the compiler which allows us to achieve the same kind of result even though the class is sealed.

What we need to do is write a static class as follows:

    public static class MusicAbilities
    {
        public static void PlayPiano(this Person p)
        {
            Console.WriteLine("Hey I am playing the piano!");
        }
 
        public static void PlayPiano(this Person p, string songName)
        {
            Console.WriteLine("Hey I am playing \"" + songName + "\"");
        }
    }


So what we do then is create a new class with a sensible name - a name which describes what abilities we are adding.  The class has to be static.  The static keyword when used with a class just means that the class contains nothing but static members and so you cannot create an instance of this.

We then write the methods we require to be added to our sealed class.  These also need to be static and the first parameter of the method must be the type we are extending.  It must also be preceded with a "this" keyword.  The p in our example is of course just a variable name.

And that is all we need to do.  We can now run this code:

    class Program
    {
        static void Main(string[] args)
        {
            Person dave = new Person();
 
            dave.PayTaxes();
            dave.Eat();
 
            dave.PlayPiano();
            dave.PlayPiano("I am like a bird");
 
            Console.Read();
        }
    }


The output from running this will then look like this:

 And if we look at our intellisense in Visual Studio we see the following:

So our class is behaving just as if we really have given it new methods.  Now I'm pretty sure that under the hood there is some smoke and mirrors going off but that doesn't really matter as long as it works.

We can even add these methods to intrinsic classes.  Lets give musical abilities to a SqlConnection object!  Microsoft have made this class sealed so we can't extend it but with extension methods its easy - we just add another method to our static MusicAbilities class which refers to a SqlConnection as follows:

    public static class MusicAbilities
    {
        public static void PlayPiano(this Person p)
        {
            Console.WriteLine("Hey I am playing the piano!");
        }
 
        public static void PlayPiano(this Person p, string songName)
        {
            Console.WriteLine("Hey I am playing \"" + songName + "\"");
        }
 
        public static void PlayPiano(this System.Data.SqlClient.SqlConnection s)
        {
            Console.WriteLine("Hey I am playing the piano!");
        }
    }


We can then run this:

    class Program
    {
        static void Main(string[] args)
        {
            System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection();
 
            conn.PlayPiano();
 
            Console.Read();
        }
    }


And that will work fine.

Now supposing our method needs to interact with other class members?  Well we can do this since our extension method receives a reference to the class we are extending.  For example we can do this:

        public static void PlayPiano(this System.Data.SqlClient.SqlConnection s)
        {
            Console.WriteLine("Hey I am playing the piano! Also my PacketSize is " + s.PacketSize.ToString());
        }


So this works fine and we get the following output:

However there is a snag. Consider the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace StaticClasses
{
    class Program
    {
        static void Main(string[] args)
        {
            Person dave = new Person();
 
            dave.PayTaxes();
            dave.Eat();
 
            dave.PlayPiano();
            dave.PlayPiano("I am like a bird");
 
            Console.Read();
        }
    }
 
    public sealed class Person
    {
        private int legs = 2;
 
        public void PayTaxes()
        {
            Console.WriteLine("I am paying my taxes");
        }
 
        public void Eat()
        {
            Console.WriteLine("Munch munch");
        }
    }
 
    public static class MusicAbilities
    {
        public static void PlayPiano(this Person p)
        {
            Console.WriteLine("Hey I am playing the piano! I also have " + p.legs.ToString() + " legs");
        }
 
        public static void PlayPiano(this Person p, string songName)
        {
            Console.WriteLine("Hey I am playing \"" + songName + "\"");
        }
 
        public static void PlayPiano(this System.Data.SqlClient.SqlConnection s)
        {
            Console.WriteLine("Hey I am playing the piano!");
        }
    }
}
 


This code won't even compile as it says that:

'StaticClasses.Person.legs' is inaccessible due to its protection level


Changing this to protected too gives the same result but with an extra error message since declaring a protected field in a sealed class makes no sense! So our reference passed in to our extension method appears to be just a normal reference.  In other words our extension method is not really running in the context of the actual sealed class otherwise it would be able to access the legs field.  So I guess this is the smoke and mirrors I was hinting at.

So in summary Extension methods can be useful but should generally be a last resort and only used with sealed classes.  If a class is not sealed then simply sub class it.  You can also consider extending a class using composition but that will be in another article.

Leave a comment

Name

Email (optional and not disclosed)



Email address is not disclosed but just used to alert you of new posts if entered
Word CV
HTML CV
PDF CV
Text CV
CMS Lite
ETraining
Planet Health
Florida Health
the Date Shack
Taylors
Emcat
Emtex
Browne Jacobson
Alliance & Leicester
Baird Leisure
Swarfega
Creature Comforts
Rugeley Chess Club
Katnip
Katmaid
Dudley NHS
Contact Me
Current Status