C#語法之擴展


擴展方法使你能夠向現有類型“添加”方法,而無需創建新的派生類型、重新編譯或以其他方式修改原始類型。 擴展方法是一種特殊的靜態方法,但可以像擴展類型上的實例方法一樣進行調用。這是msdn的描述。上面幾句我看好多博客都是這樣開頭的。所以我也這樣開頭。

原本想着上一篇博客回顧了下泛型,將具體的模糊化,這個應該講反射,將模糊的具體化,不過呢看了下反射東西不少,一晚上我也總結不完,還要留點時間打飛機呢。於是想了想就總結下擴展吧。

一、為什么要有擴展方法?

開頭也說了,無需創建新的派生類型、重新編譯或其他方式修改原始類型給現有類或接口添加方法。比如在沒有擴展之前,會經常有一些helper工具類,例如處理字符串、時間的。有了擴展我們可以直接擴展字符串類或時間類就可以了,這樣不用在實例化helper類就能直接處理。

二、擴展方法有什么特征?

擴展方法是靜態方法,是類的一部分,但是實際上沒有放在類的源代碼中。
擴展方法所在的類也必須被聲明為static
C#只支持擴展方法,不支持擴展屬性、擴展事件等。
擴展方法的第一個參數是要擴展的類型,放在this關鍵字的后面,this后面的參數不屬於方法的參數
在擴展方法中,可以訪問擴展類型的所有公共方法和屬性。
擴展方法擴展自哪個類型,就必須是此類型的變量來使用,其他類型無法使用
如果擴展方法和實例方法具有相同的簽名,則優先調用實例方法
擴展自父類上的方法,可以被子類的對象直接使用
擴展自接口上的方法,可以被實現類的對象直接使用
擴展方法最終還是被編譯器編譯成:靜態類.靜態方法()

三、demo

上面幾句基本總結把擴展總結完了,下面做一個demo來說明一下。

1.定義IAnimal接口 聲明void Eat();方法

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

namespace ExtensionMethod
{
    public interface IAnimal
    {
        void Eat();
    }
}

2.定義Person類實現接口IAnimal實現void Eat();方法

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

namespace ExtensionMethod
{
    public class Person:IAnimal
    {
        public void Eat()
        {
            Console.WriteLine("Person Eat");
        }
    }
}

3.定義擴展方法ExtensionMethod

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

namespace ExtensionMethod
{
    public static class ExtensionMethod
    {
        public static void Eat(this IAnimal iAnimal)
        {
            Console.WriteLine("IAnimalExtension Eat");
        }
        public static void Sleep(this IAnimal iAnimal)
        {
            Console.WriteLine("IAnimalExtension Sleep");
        }
        public static void Eat(this Person person)
        {
            Console.WriteLine("PersonExtension Eat");
        }
        public static void Sleep(this Person person)
        {
            Console.WriteLine("PersonExtension Sleep");
        }
    }

}

上面在ExtensionMethod類中定義了4個擴展方法,兩個是對接口IAnimal的擴展,兩個是對Person類的擴展。

4.實例化測試

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


namespace ExtensionMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            IAnimal p = new Person();
            p.Eat();
            p.Sleep();
            Console.WriteLine("----------------這是底線------------------------");
            Person p1 = new Person();
            p1.Eat();
            p1.Sleep();
            Console.WriteLine("----------------這是底線------------------------");

            ExtensionMethod.Eat(p);
            ExtensionMethod.Sleep(p);
            Console.WriteLine("----------------這是底線------------------------");
            ExtensionMethod.Eat(p1);
            ExtensionMethod.Sleep(p1);
            Console.ReadLine();
        }
    }
}

上面Mian方法中,首先實例化了一個Person對象,賦值給IAnimal類型的變量,調用Eat()和Sleep()方法。然后又實例化了一個Person對象,這次賦值給Person類型的變量。

下面來看下運行結果是不是出乎意料:

p和p1我們可以對比着來分析,對於Eat()方法都是輸出"Person Eat",如果擴展方法和實例方法具有相同的簽名,則優先調用實例方法,這句話正好能解釋為什么。但是對於Sleep()方法,我們可以看到使用IAnimal類型的變量調用的是接口的擴展方法,使用Person類型的變量調用的是Person類型的擴展方法。擴展方法擴展自哪個類型,就必須是此類型的變量來使用,其他類型無法使用,與這句雖然有點出入,但也是蠻符合的。我是這樣理解的:對於同名方法,實例方法優先擴展方法,自身擴展方法優先父類方法。 也可能是因為子類覆蓋了父類的擴展方法。

我們可以把Person對的擴展方法注釋,然后看下運行結果。

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

namespace ExtensionMethod
{
    public static class ExtensionMethod
    {
        public static void Eat(this IAnimal iAnimal)
        {
            Console.WriteLine("IAnimalExtension Eat");
        }
        public static void Sleep(this IAnimal iAnimal)
        {
            Console.WriteLine("IAnimalExtension Sleep");
        }
        //public static void Eat(this Person person)
        //{
        //    Console.WriteLine("PersonExtension Eat");
        //}
        //public static void Sleep(this Person person)
        //{
        //    Console.WriteLine("PersonExtension Sleep");
        //}
    }

}

從上面的結果可以看到,擴展自接口上的方法,可以被實現類的對象直接使用,其實擴展自父類上的方法,可以被子類的對象直接使用和接口類似

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM