26.1 Extension methods擴充函數
Extension methods are static methods that can be invoked using instance method syntax. In effect, extension methods make it possible to extend existing types and constructed types with additional methods.
擴充函數是static函數,它能夠使用執行個體函數句法調用。擴充函數有效地使得擴充現有類型以及使用額外函數構造類型變為可能
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.
其餘類型的擴充成員,例如屬性,事件,以及操作符,正在考慮中,但是現在還不被(編譯器)支援。
26.1.1 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:
擴充函數使用特定的關鍵字this作為修飾符應用於函數的第一個參數來聲明。擴充函數只能聲明在static的類中,以下是一個static類,聲明兩個擴充函數的例子:
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 ArgumentException();
T[] result = new T[count];
Array.Copy(source, index, result, 0, count);
return result;
}
}
}
Extension methods have all the capabilities of regular static methods. In addition, once imported, extension methods can be invoked using instance method syntax.
擴充函數具有常規static函數的一切能力。額外的,一旦匯入,擴充函數能夠被使用執行個體函數的句法所調用。
26.1.2 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-directive
擴充函數通過using-namespace-directives (§9.3.2)匯入。另外匯入的有,該namespace所包含的類型,using-namespace-directive 匯入所有的擴充函數在該namespace中的所有static類。被匯入的擴充函數有效地作為在某些類型上的額外函數,這是通過它們的第一個關鍵字以及比常規的執行個體函數更低的優先順序所給與的。例如,當Acme.Utilities namespace在下面這個例子的開頭被使用 using-namespace-directive匯入後,
using Acme.Utilities;
it becomes possible to invoke the extension methods in the static class Extensions using instance method syntax:
這使得通過執行個體函數句法調用static類Extensions 的擴充函數成為可能:
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)
26.1.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 forms
擴充函數調用的詳細規則將在下面描述。在函數調用(§7.5.5.1)任一形式中
expr . 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.
重寫的格式是被視作static函數調用處理,除非identifier被解析:開始使用最近的namespace聲明,接著使用次近namespace聲明,最後包含編譯單元,逐次嘗試被用來處理重寫函數調用,這是通過一個函數群實現的,該函數群由所有準入的擴充函數所組成,它的名稱是由identifier給與的,identifier匯入是由名稱空間聲明的using-namespace-directives實現的。第一個函數群產生一套非空的候選函數,其中有一個函數會被選中,來作為重寫函數的調用。如果所有的嘗試都產生空的候選函數,這將導致一個編譯時間刻的錯誤。
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.
在例子中,B的函數優先於前面的擴充函數,並且C的函數優先於所有的擴充函數。