Note Extension methods are less discoverable and more limited in functionality than instance methods. For those reasons, it is recommended that extension methods be used sparingly and only in situations where instance methods are not feasible or possible.
Extension members of other kinds, such as properties, events, and operators, are being considered but are currently not supported.
Declaring Extension Methods
Extension methods are declared by specifying the keyword this as a modifier on the first parameter of the methods. Extension methods can only be declared in static classes. The following is an example of a static class that declares two extension methods:namespace Acme.Utilities { public static class Extensions { public static int ToInt32(this string s) { return Int32.Parse(s); } public static T[] SliceExtension methods have all the capabilities of regular static methods. In addition, once imported, extension methods can be invoked using instance method syntax.(this T[] source, int index, int count) { if (index < 0 || count < 0 || source.Length – index < count) throw new ArgumentException(); T[] result = new T[count]; Array.Copy(source, index, result, 0, count); return result; } } }
Importing Extension Methods
Extension methods are imported through using-namespace-directives (§9.3.2). In addition to importing the types contained in a namespace, a using-namespace-directive imports all extension methods in all static classes in the namespace. In effect, imported extension methods appear as additional methods on the types that are given by their first parameter and have lower precedence than regular instance methods. For example, when the Acme.Utilities namespace from the example above is imported with the using-namespace-directiveusing Acme.Utilities;it becomes possible to invoke the extension methods in the static class Extensions using instance method syntax:
string s = "1234"; int i = s.ToInt32(); // Same as Extensions.ToInt32(s) int[] digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int[] a = digits.Slice(4, 3); // Same as Extensions.Slice(digits, 4, 3)
Extension Method Invocations
The detailed rules for extension method invocation are described in the following. In a method invocation (§7.5.5.1) of one of the formsexpr . identifier ( ) expr . identifier ( args ) expr . identifier < typeargs > ( ) expr . identifier < typeargs > ( args )if the normal processing of the invocation finds no applicable instance methods (specifically, if the set of candidate methods for the invocation is empty), an attempt is made to process the construct as an extension method invocation. The method invocation is first rewritten to one of the following, respectively:
identifier ( expr ) identifier ( expr , args ) identifier < typeargs > ( expr ) identifier < typeargs > ( expr , args )The rewritten form is then processed as a static method invocation, except for the way in which identifier is resolved: Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to process the rewritten method invocation with a method group consisting of all accessible extension methods with the name given by identifier imported by the namespace declaration's using-namespace-directives. The first method group that yields a non-empty set of candidate methods is the one chosen for the rewritten method invocation. If all attempts yield empty sets of candidate methods, a compile-time error occurs.
The preceeding rules mean that instance methods take precedence over extension methods, and extension methods imported in inner namespace declarations take precedence over extension methods imported in outer namespace declarations. For example:
using N1; namespace N1 { public static class E { public static void F(this object obj, int i) { } public static void F(this object obj, string s) { } } } class A { } class B { public void F(int i) { } } class C { public void F(object obj) { } } class X { static void Test(A a, B b, C c) { a.F(1); // E.F(object, int) a.F("hello"); // E.F(object, string) b.F(1); // B.F(int) b.F("hello"); // E.F(object, string) c.F(1); // C.F(object) c.F("hello"); // C.F(object) } }In the example, B's method takes precedence over the first extension method, and C's method takes precedence over both extension methods.
No comments:
Post a Comment