C# Partial Specialization With Extension Methods

One of the things C# generics lacks (compared to C++ templates) is specialization (neither explicit nor partial). This can be very useful in some cases where you want to perform something differently for a specific T in a Class<T>.

With C# 3.0, there is a relatively easy way to achieve this, albeit not optimal, for reasons I'll specify later on. Take a look at the following piece of code:

 

    public class SomeClass<T>

    {

        private readonly List<T> items = new List<T>();

 

        internal void AddInternal(T item)

        {

            items.Add(item);

        }

    }

 

    [EditorBrowsable(EditorBrowsableState.Never)]

    public static class SomeClassExtensions

    {

        public static void Add<T>(this SomeClass<T> c, T item)

        {

            c.AddInternal(item);

        }

 

        public static void Add(this SomeClass<int> c, int item)

        {

            if (item <= 0)

            {

                throw new ArgumentOutOfRangeException("item", "Value must be a positive integer.");

            }

            c.AddInternal(item);

        }

    }

 

Instead of placing the Add method in SomeClass<T>, we put it in a static class that has extension methods. This allows the compiler to select the appropriate method according to the type parameter. (Side note: I've specified the EditorBrowsable attribute so that the class with the extensions would not appear in VS intellisense.)

The biggest caveat about this is that extension methods do no have access to private members, so the only option is to make the members internal, which, in many cases, leads to a bad design. If only extension method classes could be written as inner classes...

Also, extension methods, being static, could not be virtualized. You can, however, make the internal method "protected internal virtual".

Published Wednesday, November 21, 2007 11:46 PM by aelij
Filed under: ,

Comments

# re: C# Partial Specialization With Extension Methods

Sunday, August 24, 2008 8:16 AM by Peter Verswyvelen

Hi aelij,

Nice hack! Will come in handy.

But it works only partially.

E.g. when you try it with the following program:

static void main()

{

 var c = new SomeClass<float>();

 c.Add((float)-1);

 c.Add((int)-1);

}

the generic Add method is always called (the int is silently converted to a float?), so no specialization takes place as in C++.

# re: C# Partial Specialization With Extension Methods

Wednesday, September 10, 2008 1:57 PM by aelij

Hi Peter,

It's not supposed to work. The specialization is for an instance of SomeClass<T>, not for each call to the Add() method. So, if you create a SomeClass<int>, the compiler will select the most specialized method.

Aelij.

# re: C# Partial Specialization With Extension Methods

Wednesday, December 24, 2008 1:12 AM by Ernst-Jan

Hi aelij,

Nice solution, but I think there is an issue if you try to use it from another generic function. For instance the code below will not call the overload:

void foo<T>(T t)

{

  SomeClass<T> o = new SomeClass<T>();

  0.Add(t);

}

static void main()

{

  foo<int>(3); // calls SomeClassExtensions<T> instead of override

}

I think a better approach is the following:

   class SomeType

   {

   }

   class Foo<T>

   {

       public static Foo<T> CreateInstance()

       {

           if (typeof(T) == typeof(SomeType)) return new FooSomeType() as Foo<T>;

           return new Foo<T>();

       }

       protected Foo()

       { }

       public virtual void SomeMethod()

       {

           // what ever

       }

       private class FooSomeType : Foo<SomeType>

       {

           public override void SomeMethod()

           {

               // SomeType specific handling goed here

           }

       }

   }

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Please add 2 and 4 and type the answer here:

Enter the numbers above: