Extension methods (advanced)
Overriding methods is old-fashioned, well-known and broadly used.
Since .NET 4.0 extension methods were added. You can now easily add new capabilities to existing types like classes, structs or interfaces.
Extension methods are defined as static methods but are called by using instance method syntax, their scope is their namespace. You have to explicitly import the namespace with a using directive unless you are in the right namespace already.
First of all you need to generate a static class, which is neither generic nor nested. Then use the this keyword on the first parameter of a static method.
namespace WeAreInTheSameNamespace { public static class ExtendingExistingTypes { public static double DoSomething(this double x, double y, int z) { return x * y * z; } // } // class public static class ExtendingExistingTypesTest { public static void Test() { double x = 5.0; double r; r = x.DoSomething(4.0, 2); // static method called like an instance Console.WriteLine(r); // = 40 r = ExtendingExistingTypes.DoSomething(6.0, 7.0, 1); Console.WriteLine(r); // = 42 Console.ReadLine(); } // } /// } // namespace
Did you realize the this keyword in public static double DoSomething(this double x, double y, int z) {}? It tells the compiler:
- If someone uses the method DoSomething() as a standard static method, simply ignore the this keyword.
- If the method is used like an instance method, then the first parameter is the instance itself. The second parameter becomes the first parameter.
Therefore we only have 2 parameters in the first method call [r = x.DoSomething(4.0, 2);] and 3 parameters in the second method call [r = ExtendingExistingTypes.DoSomething(6.0, 7.0, 1);].
The this keyword defines the type it is extending.
Have you seen such before? Sure, the most common extension methods are defined in interface IEnumerable. You probably just haven’t looked at them this way.
public static void Test2() { IEnumerable<double> lList = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }; double d = lList.Average(); // extension method of an interface Console.WriteLine(d); Console.ReadLine(); } //
To avoid trouble you should be aware that extension methods have a lower priority than existing method signatures. Trying to override an existing method signature in an interface, struct or class is nonsense and will, due to its lower priority, never be called!
Extension methods are very useful when you cannot change the source code (eg. you don’t have the code of a library), but want to associate a new method with eg. the existing class without using override.
namespace NMyInterface { public interface IMyInterface { void MethodB(); } // interface } // namespace // Define extension methods for IMyInterface. namespace NCoolExtensions { using NMyInterface; public static class MyExtension { public static void MethodA(this IMyInterface x, double d) { Console.WriteLine("Extension MethodA, double"); } public static void MethodA(this IMyInterface x, int i) { Console.WriteLine("Extension Method A, int"); } // Nonsense signature, the method will never be called because of its lower priority. public static void MethodB(this IMyInterface x) { Console.WriteLine("Extension nonsense"); } } // class } // namespace namespace NTestArea { using NCoolExtensions; using NMyInterface; class A : IMyInterface { public void MethodB() { Console.WriteLine("MethodB"); } } // class class B : IMyInterface { public void MethodA(int i) { Console.WriteLine("MethodA"); } public void MethodB() { Console.WriteLine("MethodB"); } } // class class C : IMyInterface { public void MethodA(object o) { Console.WriteLine("MethodA"); } public void MethodB() { Console.WriteLine("MethodB"); } } // class class D { public static void Test3() { Console.WriteLine("Class A"); A a = new A(); a.MethodA(2); a.MethodA(2.0); a.MethodB(); Console.WriteLine("Class B"); B b = new B(); b.MethodA(2); b.MethodA(2.0); b.MethodB(); Console.WriteLine("Class C"); C c = new C(); c.MethodA(2); c.MethodA(2.0); c.MethodA(new object()); c.MethodB(); } // } // class } // namespace
example output:
Class A
Extension Method A, int
Extension MethodA, double
MethodB
Class B
MethodA
Extension MethodA, double
MethodB
Class C
MethodA
MethodA
MethodA
MethodB
Have a look at the output of Class C. MethodA(object o) hides all extension methods. Be cautious!
Posted on January 6, 2014, in Advanced, C#, Interfaces and tagged advanced, C#, C-sharp, Extension Methods, programming, Source code. Bookmark the permalink. 3 Comments.
Pingback: Explicit interface implementations (basic) | C# Hardcore Programming
Pingback: Reflection (part 5, professional), CodeDOM (& lambda expression tree) | C# Hardcore Programming
Pingback: Cascade pattern / Method chaining | C# Hardcore Programming