Specification
Original: "C # Version 3.0 Specification", Microsoft
Translation: Lover_p
An extension method (Extension Methods) is a static method that can be invoked through the syntax of an instance method. In the final effect, the extension method makes it possible to extend an existing type and construct a type with additional methods to become a reality.
Attention
Extension methods are difficult to detect and have a significant functional limitation over instance methods. For these reasons, we recommend that you use extended methods conservatively, only when the instance method is not feasible or is not feasible at all.
Other types of extended members, such as properties, events, and operators are considered, but are not currently supported.
2.1 Declaration Extension method
Extension methods are declared by specifying the keyword this as a modifier on the first parameter of the method. Extension methods can only be declared in static classes. The following example is 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[] Slice<t> (this t[] source, int index, int count) {
if (Index < 0 | | | Count < 0 | | source. Length-index < count)
throw new Arugmentexception ();
T[] result = new T[count];
Array.copy (source, index, result, 0, count);
return result;
}
}
}
Extension methods have exactly the same functionality as normal static methods. In addition, once an extension method is imported, the extension method can be invoked using the syntax of the calling instance method.
2.2 Import extension methods
Extension methods are imported using Using-namespace-directives. In addition to importing types in a namespace, a using-namespace-directive can also import all extension methods in all static classes in a namespace. Finally, the imported extension method behaves as an additional method of the type of its first parameter, and its precedence is lower than the normal instance method. For example, when using Using-namespace-directive to import the Acme.utilities namespace in the example above:
Using Acme.utilities;
You can invoke the extension method in the static class extensions by using the syntax of the calling instance method:
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)
2.3 Call to extension method
The detailed rules for extending method calls are described below. In the following form of method invocation:
Expr. Identifier ()
Expr. Identifier (args)
Expr. Identifier < Typeargs > ()
Expr. Identifier < Typeargs > (args)
If no available instance methods are found in the normal process (specifically, when the set of candidate methods to be called is empty), an extension method call is attempted. These method calls are first rewritten to the appropriate form below:
Identifier (expr)
Identifier (expr, args)
Identifier < Typeargs > (expr)
Identifier < Typeargs > (expr, args)
The rewritten form is then processed as a static method call, and identifier is parsed in the following order: first, the closest declaration in the namespace life, followed by each close namespace, and finally the compilation unit that contains the code, in which repeated attempts are made to rewrite the method calls. These methods come from a method group that consists of the visible extension methods provided by all the visible identifier in the namespace imported by Using-namespace-directives. The first method group that produces a set of Non-null candidate methods is a selection of the flushing method invocation. If all attempts produce an empty set of candidate methods, a compile-time error occurs.
The above rules mean that instance methods have precedence over extension methods, and that the extension methods in the namespace that are introduced last are more precedence than the extension methods in the namespaces that are introduced in the first place. 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 this example, the B method takes precedence over the first extension method, whereas the C method takes precedence over all two extension methods.