LINQ Farm: Extension Methods and Scoping


There are a few scoping rules that you must keep in mind when using extensions methods. Problems with scoping and extensions methods are rare, but when you encounter them they are quite vexing.

An instance method will always be called before an extension method. The runtime looks first for an instance method, if it finds an instance method with the right name and signature, it executes it and never looks for your extension method. The following code illustrates this problem:

using System;

namespace ConsoleApplication1
{
    public class MyClass
    {
        public void DoThis()
        {
            Console.WriteLine("MyClass.DoThis");
        }
    }


    public static class MyExtensions01
    {
        // Can never be called as if it were an instance method of MyClass.
        public static void DoThis(this MyClass myClass)
        {
            Console.WriteLine("MyExtensions01.DoThis");
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass = new MyClass();
            myClass.DoThis();                // Calls MyClass.DoThis
            MyExtensions01.DoThis(myClass);  // Calls MyExtensions01.DoThis
        }
    }
}

MyExtensions01.DoThis is a valid extension method for MyClass. However, it will never be called because MyClass.DoThis always takes precedence over it unless you explicitely call it as a static method of MyExtensions01.

In cases where you have two extension methods with the same name, an extension method in the current namespace will win out over one in another namespace. Ambiguity will become an issue, however, when you try to call two extension methods with the same name and signature in the same namespace, or in two different namespaces both used by the current namespace. See Listing 5 for an example of this problem.

The following code will not compile because the compiler finds the call to DoThat ambiguous:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ExtensionScope
{
    public class MyClass
    {
        public void DoThis()
        {
            Console.WriteLine("Do this");
        }
    }
}

namespace Extensions01
{
    using ExtensionScope;

    public static class MyExtensions01
    {
        // Can never be called
        public static void DoThis(this MyClass myClass)
        {
            Console.WriteLine("Do this");
        }

        public static void DoThat(this MyClass myClass)
        {
            Console.WriteLine("Do bop");
        }
    }
}

namespace Extensions02
{
    using ExtensionScope;

    public static class MyExtensions02
    {
        // Can never be called
        public static void DoThis(this MyClass myClass)
        {
            Console.WriteLine("Do this");
        }

        public static void DoThat(this MyClass myClass)
        {
            Console.WriteLine("Do bang");
        }
    }
}

namespace ExtensionScope
{
    using Extensions01;
    using Extensions02;

    class Program
    {
        static void Main(string[] args)
        {
            MyClass m = new MyClass();
            m.DoThat();
        }
    }
}

This program throws a compile time error because the compiler does not know if you want to MyExtionsions01.DoThat() or MyExtension02.DoThat(). There are two ways to resolve this error:

  • You could remove the using directive for either Extensions01 or Extensions02. In this case, that would be a fine resolution, but if there were other methods or classes in both Extensions01 and Extensions02 that you wanted to use, then this could become a painful, or even unacceptable, choice.
  • You could explicitly state which method you want to call using standard static syntax: MyExtensions01.DoThat(m).
  • You could move either MyExtensions02 or MyExtensions01 into the ExtensionScope namespace: 
namespace ExtensionScope
{
    public static class MyExtensions02
    {
        public static void DoThat(this MyClass myClass)
        {
            Console.WriteLine("MyExtensions02.DoThat");
        }
    }
}

This latter solution works so long as you have access to the source.

It should be clear that some of the issues discussed here can lead to trouble if you are not careful. In particular, you don’t want to end up in a situation where forcing someone to remove a namespace results in them losing access to important functionality, nor do you want to force them to choose between functionality they desire and using your extensions.

It can also be a serious nuisance if you muddy a namespace with what many developers might consider superfluous methods. If you added 50 extension methods to the C# string class, then developers who just want to access the base functionality of that object would always have to contend with your methods, particularly when using IntelliSense.

To avoid or at least mitigate the seriousness of these problems, you should always place your extension methods in unique namespace separated from the rest of your code so that you can easily include or exclude the extension methods from a program. Listings 10 and 11 illustrate this technique.

Place your extensions in a separate file, and give them a unique namespace:

namespace MyCode
{
    public class MyCode
    {
        // Code omitted here
    }
   
}
namespace MyCode.Extensions
{
    public static class SpecialString
    {
        private static string[] stateCodes = 
                {"AL","AK","AZ","AR","CA","CO","CT","DE","FL",
                 "GA","HI","ID","IL","IN","IA","KS","KY","LA",
                 "ME","MD","MA","MI","MN","MS","MO","MT","NE",
                 "NV","NH","NJ","NM","NY","NC","ND","OH","OK",
                 "OR","PA","RI","SC","SD","TN","TX","UT","VT",
                 "VA","WA","WV","WI","WY"};

        public static bool IsState01(this string source)
        {
            if (source == null) return false;
            source = source.ToUpper(); 
            foreach (var item in stateCodes)
            {
                if (source == item)
                {
                    return true;
                }
            }
            return false;
        }

        public static bool IsState02(this string source)
        {
            return (source == null) ? false : stateCodes.Contains(source.ToUpper());
        }
    }
}

In this code I show you two alternative ways to implement the IsState extension method. The second, which uses LINQ, is probably easier to maintain. You can access the extension methods in a namespace MyCode.Extensions like this:

using System;
using MyCode;
using MyCode.Extensions;

namespace ConsoleApplication1
{
    class Program
    {            
        static void Main(string[] args)
        {
            MyCode myCode = new MyCode();
            // Use My Code here.
            string test = "WA";
            if (test.IsState02())
            {
                Console.WriteLine("{0} is a state", test);
            }
        }
    }
}

In this code your extension method is available and the code compiles. Comment out the third using statement and your extension method would not be available and the code would not compile. The developer would, however, still have access to the functionality found in the MyCode namespace. You could perhaps improve this technology by putting your extensions in their own assembly with its own namespace. You could then be sure that developers could choose to include or exclude the extra weight of your extension methods when they ship their code.

Though extension methods are particularly useful in LINQ, they are now a part of the language, and if used with caution, they can be useful. Placing them in their own namespace is a best practice that should help you get the most from this feature.

kick it on DotNetKicks.com

Comments (11)

  1. You’ve been kicked (a good thing) – Trackback from DotNetKicks.com

  2. TraumaPony says:

    Uh… Is it just me, or is IsState not an extension method?

  3. ccalvert says:

    Thanks TraumaPony. I was experiementing with it and changed it back and forth, and forgot to change it back. Should be fixed now.

  4. Bad Habits says:

    source.ToUpper().Equals(item)???

    Oh, sure, that’s much better than StringComparison.

  5. Jon Skeet says:

    A couple of nitpicks and a more general point:

    1) "You could remove the using statement for either Bop or Bang." You mean a using directive. I think we’ve all made this mistake :)

    2) There’s a third way of resolving the ambiguity: call the method as a normal static method. It’s worth remembering that extension methods don’t *have* to be called as if they were instance methods.

    3) Why was the feature designed this way? I’ve ranted about this several times, but never discovered why extension methods are discovered by namespace, and with the same syntax as introducing namespaces. If instead of that we had:

    using static Bop.MyExtensions01;

    to introduce all the extension methods in Bop.MyExtensions1 it would be a lot easier to control which extension methods were available without adding extra namespaces all over the place. That’s not the only way of solving the problem, of course – it’s just a fairly obvious one.

    This wasn’t an unknown problem when C# 3 was released – I remember many of us at the MVP summit in 2005 requesting this change. My experience is that the language designers generally weigh up decisions pretty carefully, so I suspect there are reasons behind the decision – but I’d love to hear them.

    Of course, just because we have the current syntax doesn’t mean that additional syntax couldn’t be added to give fine-grained control. It wouldn’t be ideal, but it would be better than the current situation.

    </soapbox>

  6. Syed says:

    Sir

    would u please send me the C# various queries to bring a command over LinQ

    best regards

    Syed

  7. ccalvert says:

    Jon,

    Thanks for the comment on *using statements* vs *using directives*. In my old Delphi days, *using statements* was correct, and some old habits die hard. In C#, there are *using statements* that are part of method bodies, and so we need a way to distinguish the two items. You are therefore right to point out that *directive* is the correct term. I’ve updated the text accordingly.

    I understand and sympathize with your desire to have a way to include a switch that allows you to specify whether or not to bring in the extension methods in a namespace. The language designers certainly heard comments like yours on this issue, but ultimately they opted not to use that kind of switch, as outlined above. Their decision has several consequences:

    1) It keeps the language as simple and clean as possible. Every new switch is something that new users need to master, and another detail which developers must track. There is always a good argument for adding any one switch. Problems can occur, however, if this process incrementally leads the designers to add hundreds of switches, making the language potentially unwieldy.

    2) Another potential problem could arise if a library designer opted to use the technique shown above in my post, but the user tried to use switches to turn extension methods on and off, or vice versa. Then you could end up with the switch being used in places where it was not needed, and left off where it was needed. All that could lead to confusion.

    3) The method the designers of the C# language chose ultimately puts the burden squarely on the shoulders of the designer of a library. A well designed library makes it easy for users of the library to include or exclude extension methods, as described above. It also gives developers of a library the option of forcing users to include the extension methods, if the library designer feels that his library can’t be used without them.

    In saying all this, I don’t mean to imply that your comments are off-base or ill-considered. This is a complicated issue, and your suggestion does have real merit. I believe, however, that ultimately the C# team made a good call on this one.

    – Charlie

  8. ccalvert says:

    Syed,

    One of the best ways to get up to speed on LINQ is to look at the SampleQueries project that ships with the C# samples that accompany Visual Studio 2008. In Visual Studio, choose Help | Samples from the menu, and read the instructions to download or locate the C# samples. Unzip the CSharpSamples.zip file, and locate the SampleQueries project in the LinqSamples directory. That project has over 100 examples of how to use LINQ with each of its major providers: LINQ to SQL, LINQ to XML, LINQ to Objects, and LINQ to DataSet. It ends up being some 500 different samples all rolled into one project.

    – Charlie

  9. VInicius says:

    Charlie,

    I have a in c# form with the file form1.designer.cs and i would like to put a extension method in this file. When i do this and change the form to view designer i have a crash in my application and i can’t see the designer of this form. Can´t i use extension methods in view designer ?

    Vinicius

  10. Molden Molsen says:

    Gathering all this is neat! I suppose appling will also get me into doing more Shortly

  11. kazim says:

    i also experience the same behavior as Vinicius encounter. Cant we use extension methods in designer.cs files ?

    kazim