C# this關鍵字(給底層類庫擴展成員方法)

本文參考自唔愛吃蘋果C#原始類型擴展方法—this參數修飾符,並在其基礎上作了一些細節上的解釋html

一、this做爲參數關鍵字的做用框架

使用this關鍵字,能夠向this關鍵字後面的類型添加擴展方法,而無需給其建立新的派生類型、從新編譯或以其餘的方式修改類型.ide

擴展方法是一種特殊的靜態方法,但能夠像實例方法那樣調用。可是this關鍵字最主要的做用是對類型的重載方法的擴充,來知足自身的需求,由於有些類方法的重載方法可能不是很完善,而直接修改類型的條件不足(應爲可能有些已經被編譯成dll,有些測試.net框架的底層類),因此只能經過this關鍵字對其進行擴展,也就是完善類方法的重載方法。函數

說了這麼多,可能你仍是不理解,如今有個需求:post

我想利用string.format拼接一個,異常字符串,具體內容是:   ("parameter {0} cannot be empty",parameter),我知道使用string.format能很好地勝任,可是string.format靜態方法我用不習慣,因此我想將它改造爲string類的實例方法,直接經過"".實例方法來調用,最後的效果就是:"parameter {0} cannot be empty".實例方法名(parameter)測試

可是我不可能修改string類,來達到這個目地,由於string類是.Net Framework的底層類庫,因此只能使用this關鍵字,來給其添加擴展方法,代碼以下:this

public static class StringUtilities
{
  public static string FormatWith(this string format,IFormatProvider provider,object org0) {
            return format.FormatWith(provider, new object[] { org0 });
  }
  public static string FormatWith(this string format, IFormatProvider provider, object[] args) {
            return string.Format(provider,format,args);
  }
}

ok,如今經過this關鍵字給string類添加了兩個實例重載方法,可是須要注意,這裏的類必須就靜態類,擴展方法必須是靜態方法,緣由以下:url

(1)、這裏傳入的須要擴展的string類型spa

不是靜態變量而是成員變量.net

(2)、靜態類的特色,若是一個靜態類沒有加構造函數,那麼編譯器會自動的給它加一個靜態構造函數,靜態構造函數是最先被調用的,只要有靜態訪問,那就先調用靜態構造函數,接着調用非靜態構造函數,並且靜態類裏面的成員在第一次被訪問以後,就會被添加到全局環境中,後面的訪問,將不會執行初始化操做,直接調用便可。並且靜態類中不能有成員變量,this關鍵字是個列外

(3)、當類是靜態類時,程序會在編譯的時候,就將全部的靜態成員編譯到全局環境中,當類不是靜態類的時候,只有當類中的靜態成員被調用以後,纔會被初始化到全局環境中,也就是說,代碼以下:

public  class StringUtilities
{
     public static string FormatWith(this string format, IFormatProvider provider, object org0)
     {
         return format.FormatWith(provider, new object[] { org0 });
     }
}

這裏的StringUtilities不是靜態類,因此只要當StringUtilities的FormatWith在被初始化以後,他纔會被初始化到全局環境中,下一次調用就不須要初始化了直接去全局環境中取,因此這個時候

這樣是調不到FormatWith方法的,應爲此時的FormatWith方法尚未被初始化,因此編譯器會報錯

,可是若是將StringUtilities改成靜態類,那麼編譯器就會在編譯完後,就將全部的靜態成員初始化到全局環境中,這樣上面出錯的代碼就沒問題了,代碼以下:

    public static class StringUtilities
    {

        public static string FormatWith(this string format, IFormatProvider provider, object org0)
        {
            return format.FormatWith(provider, new object[] { org0 });
        }

        public static string FormatWith(this string format, IFormatProvider provider, params object[] args)
        {
            DataValidate.ArgumentNotNull(format, "format");
            return string.Format(provider, format, args);
        }
    }

 

二、ok,上面的代碼完成了對string類的擴展,爲其添加了兩個擴展方法,下面經過代碼來測試是否成功

 string result = "'{0}' cannot empty".FormatWith(CultureInfo.InvariantCulture, "aaa");
 Response.Write(result);

輸出:

ok,說明實例方法擴展成功

 

總結:上面的擴展方法的調用方式,看上去像是成員方法,但實際編譯器會對this關鍵字作特殊處理,編譯器生成的中間語言(IL)會將代碼轉換爲對靜態方法的調用,

所以,並未真正違反封裝原則。實際上,擴展方法沒法訪問它們所擴展的類型中的私有變量,不信你能夠試試在擴展方法中訪問string的私有成員!!!

相關文章
相關標籤/搜索