程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 關於擴展方法,需要留意的原則和規則,擴展留意原則規則

關於擴展方法,需要留意的原則和規則,擴展留意原則規則

編輯:C#入門知識

關於擴展方法,需要留意的原則和規則,擴展留意原則規則


 

  • C#只支持擴展方法,不支持擴展屬性、擴展事件、擴展操作符
  • 擴展方法必須在非泛型的靜態類中聲明,而且擴展方法至少要有一個參數,而且只有第一個參數能用this關鍵字標記
  • C#在靜態類中查找方法時,要求靜態類本身必須具有文件作用域,即擴展方法必須在頂級靜態類中定義,而不能在嵌套的靜態的類中的定義
  • 由於靜態類可以取任何名字,所以C#編譯器要花一定的時間來尋找擴展方法,它必須檢查文件作用域中的所有靜態類,並掃描他們的所有靜態方法來查找一個匹配;

        我可不可以這樣理解,性能只是在編譯時有損失,編譯之後就和普通的靜態方法調用一樣了,沒有任何區別,之所以能得出這個結論是因為通過比較如下的兩種調用方式和對應的IL代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Extention
{
    class Program
    {
        static void Main(string[] args)
        {
            var dt = DateTime.Now;

            var dtString = dt.DT();

            var dtString1 = Extention.Extention1.DT(dt);

            var dtString2 = Extention.Extention1.DT1(dt);

            Console.ReadLine();
        }

    }

    public static class Extention1
    {
        public static string DT(this DateTime dt)
        {
            return dt.ToString();
        }
        public static string DT1(DateTime dt)
        {
            return dt.ToString();
        }
    }


}

 Main函數中對DT的三種調用生成的IL代碼如下:

 

C#編譯器是如何快速的定位擴展方法的匹配的呢?


 在C#中,一旦用this關鍵詞標記了某個靜態方法的第一個參數,編譯器就會在內部向該方法應用一個定制特性ExtensionAttribute;

另外,任何靜態類只要包含至少一個擴展方法,它的元數據也會應用這個特性,類似的,程序集中只要包含了至少一個符合上述特點的靜態類,它的元數據中也會應用這個特性,

這樣一來,如果代碼調用了一個不存在的實例方法,編譯器就能快速的掃描引用的所有程序集,判斷他們哪些包含了擴展方法,然後在這些程序集中,可以只掃描包含了擴展方法的靜態類,

在每個這樣的靜態類中,可以只掃描擴展方法來查找匹配,利用這些技術,代碼能以最快的速度編譯完畢;

.class public auto ansi abstract sealed beforefieldinit Extention.Extention1
	extends [mscorlib]System.Object
{
	.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
		01 00 00 00
	)
	// Methods
	.method public hidebysig static 
		string DT (
			valuetype [mscorlib]System.DateTime dt
		) cil managed 
	{
		.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
			01 00 00 00
		)
		// Method begins at RVA 0x2088
		// Code size 19 (0x13)
		.maxstack 1
		.locals init (
			[0] string CS$1$0000
		)

		IL_0000: nop
		IL_0001: ldarga.s dt
		IL_0003: constrained. [mscorlib]System.DateTime
		IL_0009: callvirt instance string [mscorlib]System.Object::ToString()
		IL_000e: stloc.0
		IL_000f: br.s IL_0011

		IL_0011: ldloc.0
		IL_0012: ret
	} // end of method Extention1::DT

	.method public hidebysig static 
		string DT1 (
			valuetype [mscorlib]System.DateTime dt
		) cil managed 
	{
		// Method begins at RVA 0x20a8
		// Code size 19 (0x13)
		.maxstack 1
		.locals init (
			[0] string CS$1$0000
		)

		IL_0000: nop
		IL_0001: ldarga.s dt
		IL_0003: constrained. [mscorlib]System.DateTime
		IL_0009: callvirt instance string [mscorlib]System.Object::ToString()
		IL_000e: stloc.0
		IL_000f: br.s IL_0011

		IL_0011: ldloc.0
		IL_0012: ret
	} // end of method Extention1::DT1

} // end of class Extention.Extention1
  • 多個靜態類可以定義相同的擴展方法,如果編譯器檢測到存在兩個或多個擴展方法,就會提示調用不明確,此時需要調用靜態方法語法的方式來代替實例方法語法
  • 用一個擴展方法擴展一個類型時,同時也擴展了派生類,所以不要將Object作為擴展方法的第一個參數,否則這個方法在所有表達式上都能調用
  • 擴展方法存在版本控制問題(為同一個類型定義兩個相同的擴展方法,後來者會把前面的覆蓋掉,導致行為不一致)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved