Rich Newman

June 12, 2009

Extending Classes: Extension Methods or Inheritance?

Filed under: .net, c#, dotnet — Tags: — richnewman @ 12:09 am

Introduction

Extension methods were introduced in C# 3.0 as a way of extending a class without necessarily having access to the original source code of the class.

As discussed in the C# Programming Guide on MSDN, extension methods were primarily introduced to the language to allow LINQ to add standard query operators such as GroupBy and OrderBy to any class that implements IEnumerable<T>.  This is very neat syntactically.

This article will examine how extension methods can be created and used.  It will then show one example where inheritance is probably a better approach to class extension.

Basic Usage of Extension Methods

To illustrate the basic approach to using extension methods as usual a code example is available.

This contains three projects:

  1. A ‘Core’ class library intended to represent code developed by a core group of developers and used as a library by other developers.
  2. A ‘DerivedExtended’ library that is intended to represent code extending the Core library, developed by a second group of developers.
  3. A ‘Client’ library that uses the DerivedExtended library.

Initially the Core library contains just one class with just one public property:

namespace Core
{
    public class MyCoreClass
    {
        public int CoreValue { get; set; }
    }
}

How Extension Methods Work: Writing an Extension Method

We can extend our core class in our DerivedExtended library using extension methods.  To do this clearly DerivedExtended has to reference Core.  The syntax is simple to set up an extension method:

using Core;
 
namespace DerivedExtended
{
    public static class Extended
    {
        public static void SetCoreValue(this MyCoreClass myCoreClass)
        {
            myCoreClass.CoreValue = 1;
        }
    }
}

To make this work both the class and the method in it are declared static, and we use the ‘this’ keyword on the myCoreClass parameter.  The name of the static class (‘Extended’) is not relevant for the purposes of the extension method (it’s not used to invoke it in any way).

Our extension method can only access the public interface of the class it is extending.  That is in our case it can access the CoreValue property because it is public: if it were private the extension method would not be able to set it.

How Extension Methods Work: Calling an Extension Method

We now set up client code to use this:

using System;
using DerivedExtended;
 
namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            // Instantiate the core class
            Core.MyCoreClass myCoreClass = new Core.MyCoreClass();
 
            // Call extension method
            myCoreClass.SetCoreValue();
 
            // Get property value from core class and display it
            Console.WriteLine(myCoreClass.CoreValue);
 
            Console.ReadLine();
        }
    }
}

Note the syntax for calling the SetCoreValue extension method: to the client code it looks exactly like a normal instance method on the myCoreClass instance.  Note also that we have to use ‘using DerivedExtended’ directive for the compiler to find the relevant extension method.

Clearly the code above prints ‘1’ to the console window: the extension method has set the property value as you would expect.

Why This is Fragile

Now imagine our core developers decide that they need a method to set the core value, and that the method should be setting the value to 100.  If they are library developers they may know nothing about the client code and DerivedExtended library written by the second development team.  So they make the simple change below:

namespace Core
{
    public class MyCoreClass
    {
        public int CoreValue { get; set; }
 
        public void SetCoreValue()
        {
            myCoreClass.CoreValue = 100;
        }
    }
}

Now if we run our client code we see that the behaviour has been changed: it prints out 100.  However nothing has ostensibly been broken: our DerivedExtended developers could easily rebuild against the new Core library, not spot anything had changed, and ship the code with changed behaviour.  Of course in my simple example it doesn’t look like the effects of this are likely to be catastrophic.  However because of the extension method the DerivedExtended developers now need to be much more careful when the implementation of the Core library changes.

Extension Methods or Inheritance?

Of course, in object-oriented languages we already have a means of extending a class where we don’t necessarily have access to or want to change the original source code: it’s called inheritance.

In C# and other object-oriented languages there is extensive support for allowing a base class writer to control how their class will be extended by inheritance, such as declaring methods as virtual, declaring member variables as protected and so on.  A number of our core design patterns are based around designing classes that can be extended in this way (e.g. Template Method).

Why This Isn’t a Problem with Inheritance

Now consider the same extension as above being made with inheritance.  Firstly we revert our Core class to simply have the CoreValue property:

namespace Core
{
    public class MyCoreClass
    {
        public int CoreValue { get; set; }
    }
}

Then we construct a Derived class that contains a SetCoreValue method that again sets the value to 1.  Thus we extend our code in a new library in the traditional way:

namespace DerivedExtended
{
    public class Derived : Core.MyCoreClass
    {
        public void SetCoreValue()
        {
            base.CoreValue = 1;
        }
    }
}

We can now change our client code to use this extension:

    class Program
    {
        static void Main(string[] args)
        {
            // Now consider case where we extend by inheritance
 
            // Instantiate the Derived class
            Derived derived = new Derived();
 
            // Call the derived method
            derived.SetCoreValue();
 
            // Get property value from derived class and display it
            Console.WriteLine(derived.CoreValue);
 
            Console.ReadLine();
        }
    }

}

And clearly here the code will print out ‘1’ again.

Now, as before, assume our Core library developers add a SetCoreValue method to the Core class, unaware that there already is one in the Derived class:

    public class MyCoreClass
    {
        public int CoreValue { get; set; }
 
        public void SetCoreValue()
        {
            CoreValue = 100;
        }
    }

This doesn’t change the behaviour of the existing client code, which still prints out ‘1’.  However, we get a compiler warning:

‘DerivedExtended.Derived.SetCoreValue()’ hides inherited member ‘Core.MyCoreClass.SetCoreValue()’. Use the new keyword if hiding was intended.

So not only has the code not been broken, but our DerivedExtended developers will get a warning that there is a problem when they come to recompile their code against the new library.

Note also that any code the Core developers write calling SetCoreValue on the Core class will correctly call the Core class version (they don’t know about the Derived class version so can’t want to call it).

This behaviour is deliberate: by default a method in a derived class hides rather than overrides a method with the same signature in a base class if there has been no explicit use of the ‘new’ or ‘virtual/overrides’ keywords.  This is precisely because of the circumstances with regard to extension described here.

Summary

So in summary, in the circumstances described where a development team is extending classes in a library it seems better to do this by inheritance than by extension methods.  Obviously it isn’t always possible to extend a class by inheritance and we may need to use other techniques, but in general extension methods seem fragile to me.

To an extent the same argument applies to any class in our code, whether in a library or not.  Suppose we use extension methods and then later on we alter the implementation of the class we are extending.  We can break our extension methods without necessarily noticing we have done so.  Of course this is true of any code that uses the public interface of our class if its behaviour changes, so is less valid as an argument against extension methods.

MSDN

Microsoft itself agrees with the central argument in this article.  In the page on extension methods in the C# programming guide it says:

General Guidelines

In general, we recommend that you implement extension methods sparingly and only when you have to. Whenever possible, client code that must extend an existing type should do so by creating a new type derived from the existing type. For more information, see Inheritance (C# Programming Guide).

When using an extension method to extend a type whose source code you cannot change, you run the risk that a change in the implementation of the type will cause your extension method to break.

Conclusion

Extension methods can be fragile.  My recommendation is that you don’t write your own extension methods, for the reasons explained above.

About these ads

2 Comments »

  1. You’re alive! Good post.

    Comment by Joe — June 12, 2009 @ 2:46 pm

  2. I would love to see MS extend the language very slightly to address the problem you highlight here. Something like this: http://dotnet.agilekiwi.com/blog/2006/04/extension-methods-solution.html

    Although they are in no hurry to do so, perferring instead to have people minimise their usage of extension methods (which is not a bad idea anyway).

    Comment by John Rusk — June 21, 2009 @ 10:41 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Shocking Blue Green Theme Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 80 other followers

%d bloggers like this: