views:

39

answers:

2

Hi,

I have:

  • Main Program Class - uses Library A
  • Library A - has partial classes which mix in methods from Library B
  • Library B - mix in methods & interfaces

Why would I need a using statement to LibaryB just to get their extension methods working in the main class? That is given that it's Library B that defines the classes that will be extended.

EDIT - Except from code

    // *** PROGRAM ***
    using TopologyDAL;
    using Topology;  // *** THIS WAS NEEDED TO GET EXTN METHODS APPEARING ***
    class Program
    {
        static void Main(string[] args)
        {
            var context = new Model1Container();
            Node myNode;  // ** trying to get myNode mixin methods to appear seems to need using line to point to Library B ***
         }
     }


// ** LIBRARY A
namespace TopologyDAL
{
    public partial class Node
    {
        // Auto generated from EF
    }

    public partial class Node : INode<int>   // to add extension methods from Library B
    {
        public int Key
    }
}

// ** LIBRARY B
namespace ToplogyLibrary
{
    public static class NodeExtns
    {
        public static void FromNodeMixin<T>(this INode<T> node) {
           // XXXX
        }
    }
    public interface INode<T> 
    {
        // Properties
        T Key { get; }

        // Methods
    }

}

+3  A: 

Extension methods are only available if you import the namespace that they are defined in.

Otherwise, the compiler would need to resolve against every single extension method in every single referenced library, which would slow down the compile time.
Also, that would make it impossible to use an extension method if a different namespace contains an extension method with the same signature.

In summary, extension methods are features in their own right and require their namespace to be imported; they are not automatically imported with the namespace of the class that they extend.

SLaks
Hi SLaks, but I guess I was thinking that if Library A that defined Node did the import from Library B, then why would the Program project class still have to do an import? It would seem to be better for encapsulation if it didn't no? Or should I just assume this is how C# is
Greg
Extension methods are not designed for encapsulation. You might want to put the extension methods in the same namespace as the class itself. (You can define a namespace in two different DLLs)
SLaks
+2  A: 

This is an unfortunate discoverability issue with extension methods. In order to make them available you need to add a using statement for the namespace containing the static class that has the extensions. Check out this blog about extension methods.

Here is some background on extension methods:

So how is the compiler to know which extension method to bind? The compiler looks for extension methods in the innermost namespace when the call is made for extension methods and then in all the namespaces imported by the "using" clause. This process is followed moving outward until we reach the topmost namespace.

Since extension methods can be imported in to the current context by the "using" clause and bound to any object which is assignable(see convertibility section for details) to the instance parameter, all sorts of interesting possibilities open up for extending the methods implemented by a type. This can simply be done by importing a library of extension methods and using these methods as if they were declared on a type that you don't own. This means that

  1. Depending on the library you import the code can be made to do different things.

  2. The client gets an interesting way to extend a type that he does not own.

My understanding is that using extension methods is just like using any other type, except that you can't qualify them (that is just syntactically impossible), hence the need for using statement. Since you can define multiple of them in different classes in different namespaces, the compiler needs a way to resolve ambiguity.

I envisage that in future Visual Studio will add a feature to import the right namespace when you type in the method name, in a similar way it does so for class and interface names.

Consider this scenario:

namespace FruityNamespace {
  public static class FruityExtensions {
    public static string ToFunString(this int value) {return value + " bananas"; }
  }
}

namespace VegetablNamespace {
  public static class VegetablyExtensions {
    public static string ToFunString(this int value) {return value + " carrots"; }
  }
}

//In some other source file
static void Main(/**/) {
  int things = 3;
  3.ToFunString(); //error CS1061: 'System.Int' does not contain a definition for 'ToFunString' and no extension method 'ToFunString' accepting a first argument of type 'System.Int' could be found (are you missing a using directive or an assembly reference?)
}

In order to use any of those extension methods you need to import the right namespace:

using FruityNamespace;
//OR
using VegetablyNamespace;

You might ask what happens when you import both namespaces. You get a compiler error just like this:

error CS0121: The call is ambiguous between the following methods or properties: 'VegetablNamespace.VegetablyExtensions.ToFunString(int)' and 'FruityNamespace.FruityExtensions.ToFunString(int)'
Igor Zevaka