背後的故事之 - 快樂的Lambda運算式(二)

來源:互聯網
上載者:User
上一篇 背後的故事之 – 快樂的Lambda運算式(一)我們由淺入深的分析了一下Lambda運算式。知道了它和委託以及普通方法的區別,並且通過測試對比他們之間的效能,然後我們通過IL代碼深入瞭解了Lambda運算式,以及介紹了如何在.NET中用Lambda運算式來實現JavaScript中流行的一些模式。

今天,我們接著來看Lambda運算式在.NET中還有哪些新鮮的玩法。

Lambda運算式玩轉多態

Lambda如何?多態?我們用抽象類別和虛方法了,為什麼還要用Lambda這個玩意?且看下面的代碼:

class MyBaseClass{    public Action SomeAction { get; protected set; }     public MyBaseClass()    {        SomeAction = () =>        {            //Do something!        };    }} class MyInheritedClass : MyBaseClass{    public MyInheritedClass()    {        SomeAction = () => {            //Do something different!        };    }}

我們的基類不是抽象類別,也沒有虛方法,但是把屬性通過委託的方式暴露出來,然後在子類中重新為我們的SomeAction賦予一個新的運算式。這就是我們實現多態的過程,當然父類中的SomeAction的set有protected的保護層級,不然就會被外部隨易修改了。但是這還不完美,父類的SomeAction在子類中被覆蓋之後,我們徹底訪問不到它了,要知道真實情況是我們可以通過base來訪問父類原來的方法的。接下來就是實現這個了

class MyBaseClass{    public Action SomeAction { get; private set; }     Stack<Action> previousActions;     protected void AddSomeAction(Action newMethod)    {        previousActions.Push(SomeAction);        SomeAction = newMethod;    }     protected void RemoveSomeAction()    {        if(previousActions.Count == 0)            return;         SomeAction = previousActions.Pop();    }     public MyBaseClass()    {        previousActions = new Stack<Action>();         SomeAction = () => {            //Do something!        };    }}

上面的代碼中,我們通過AddSomeAction來實現覆蓋的同時,將原來的方法儲存在previousActions中。這樣我們就可以保持兩者同時存在了。

大家知道子類是不能覆蓋父類的靜態方法的,但是假設我們想實現靜態方法的覆蓋呢?

void Main(){    var mother = HotDaughter.Activator().Message;    //mother = "I am the mother"    var create = new HotDaughter();    var daughter = HotDaughter.Activator().Message;    //daughter = "I am the daughter"} class CoolMother{    public static Func<CoolMother> Activator { get; protected set; }     //We are only doing this to avoid NULL references!    static CoolMother()    {        Activator = () => new CoolMother();    }     public CoolMother()    {        //Message of every mother        Message = "I am the mother";    }     public string Message { get; protected set; }} class HotDaughter : CoolMother{    public HotDaughter()    {        //Once this constructor has been "touched" we set the Activator ...        Activator = () => new HotDaughter();        //Message of every daughter        Message = "I am the daughter";    }}

這裡還是利用了將Lambda運算式作為屬性,可以隨時重新賦值的特點。當然這隻是一個簡單的樣本,真實項目中並不建議大家這麼去做。

方法字典

實際上這個模式我們在上一篇的返回方法中已經講到了,只是沒有這樣一個名字而已,就算是一個總結吧。故事是這樣的,你是不是經常會寫到switch-case語句的時候覺得不夠優雅?但是你又不想去整個什麼原廠模式或者策略模式,那怎麼樣讓你的代碼看起來進階一點呢?

public Action GetFinalizer(string input){    switch    {        case "random":            return () => { /* ... */ };        case "dynamic":            return () => { /* ... */ };        default:            return () => { /* ... */ };    }} //-------------------變身之後-----------------------Dictionary<string, Action> finalizers; public void BuildFinalizers(){    finalizers = new Dictionary<string, Action>();    finalizers.Add("random", () => { /* ... */ });    finalizers.Add("dynamic", () => { /* ... */ });} public Action GetFinalizer(string input){    if(finalizers.ContainsKey(input))        return finalizers[input];     return () => { /* ... */ };}

好像看起來是不一樣了,有那麼一點味道。但是一想是所有的方法都要放到那個BuildFinalizers裡面,這種組織方法實在是難以接受,我們來學學外掛程式開發的方式,讓它自己去找所有我們需要的方法。

static Dictionary<string, Action> finalizers; // 在靜態建構函式用調用這個方法public static void BuildFinalizers(){    finalizers = new Dictionary<string, Action>();     // 獲得當前運行程式集下所有的類型    var types = Assembly.GetExecutingAssembly().GetTypes();     foreach(var type in types)    {        // 檢查類型,我們可以提前定義介面或抽象類別        if(type.IsSubclassOf(typeof(MyMotherClass)))        {            // 獲得預設無參建構函式            var m = type.GetConstructor(Type.EmptyTypes);             // 調用這個預設的無參建構函式            if(m != null)            {                var instance = m.Invoke(null) as MyMotherClass;                var name = type.Name.Remove("Mother");                var method = instance.MyMethod;                finalizers.Add(name, method);            }        }    }} public Action GetFinalizer(string input){    if(finalizers.ContainsKey(input))        return finalizers[input];     return () => { /* ... */ };}

如果要實現外掛程式化的話,我們不光要能夠載入本程式集下的方法,還要能隨時甚至運行時去載入外部的方法,請繼續往下看:

internal static void BuildInitialFinalizers(){    finalizers = new Dictionary<string, Action>();    LoadPlugin(Assembly.GetExecutingAssembly());} public static void LoadPlugin(Assembly assembly){    var types = assembly.GetTypes();    foreach(var type in types)    {        if(type.IsSubclassOf(typeof(MyMotherClass)))        {            var m = type.GetConstructor(Type.EmptyTypes);             if(m != null)            {                var instance = m.Invoke(null) as MyMotherClass;                var name = type.Name.Remove("Mother");                var method = instance.MyMethod;                finalizers.Add(name, method);            }        }    }}

現在,我們就可以用這個方法,給它指定程式集去載入我們需要的東西了。

最後留給大家一個問題,我們能寫遞迴運算式嗎?下面的方法如果用運算式如何寫呢?

int factorial(int n){    if(n == 0)        return 1;    else        return n * factorial(n - 1);}

以上就是背後的故事之 - 快樂的Lambda運算式(二)的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.