Lamda演變歷史

  • .NetFramework 1.0  1.1時代

以前學習委託,大部分流程都是在這裏聲明委託,實例化的時候不得不聲明一個方法,在寫一個方法不得不傳進入,這個方法與聲明的委託參數返回值吻合,然後把這個方法傳遞進去。

namespace LamdaHistory
{
    public static class NetFramework1
    {
        public delegate void NoReturnNoPara();//聲明委託
        public delegate void NoReturnWithPara(int x, string y);//聲明委託
        public static void Show()
        {
            NoReturnNoPara method = new NoReturnNoPara(DoNothing);
            method.Invoke();

            NoReturnWithPara method2 = new NoReturnWithPara(Study);
            method2.Invoke(123, "董小姐");
        }

        private static void DoNothing()
        {
            Console.WriteLine("This is DoNothing");
        }

        private static void Study(int id, string name)
        {
            Console.WriteLine($"{id} {name} 學習.Net高級班");
        }
    }
}

如下圖所示委託編譯後從IL層面看就是一個密封的,且其繼承自MulticastDelegete的類

  • .NetFramework 2.0

1、不在像以前老老實實寫方法名稱,而是把方法體直接寫在實例化委託這裏了,前面加關鍵字delegate,匿名方法沒有名字

2、可以訪問局部變量age,如果像1.0時代,是個方法的話,沒有辦法訪問到局部變量age

namespace LamdaHistory
{
    public static class NetFramework2
    {
        public delegate void NoReturnNoPara();//聲明委託
        public delegate void NoReturnWithPara(int x, string y);//聲明委託
        public static void Show()
        {
            int age = 20;
            NoReturnNoPara method = new NoReturnNoPara(delegate {
                Console.WriteLine("This is DoNothing");
            });
            method.Invoke();

            NoReturnWithPara method2 = new NoReturnWithPara(delegate(int id,string name) {
                Console.WriteLine($"{id} {name} {age} 學習.Net高級班");
            });
            method2.Invoke(123, "董小姐");
        }
    }
}
  • .NetFramework3.0

1、把delegate關鍵字去掉,增加了一個箭頭,箭頭念goes to,這就是Lamda表達式參數列表=>方法體

amespace LamdaHistory
{
    public static class NetFramework3
    {
        public delegate void NoReturnNoPara();//聲明委託
        public delegate void NoReturnWithPara(int x, string y);//聲明委託
        public static void Show()
        {
            int age = 20;
            NoReturnNoPara method = new NoReturnNoPara(()=> {
                Console.WriteLine("This is DoNothing");
            });
            method.Invoke();

            NoReturnWithPara method2 = new NoReturnWithPara((int id,string name) => {
                Console.WriteLine($"{id} {name} {age} 學習.Net高級班");
            });
            method2.Invoke(123, "董小姐");

            //省略參數類型int和string,編譯器的語法糖,雖然沒寫,編譯時還是有的,
            //根據委託推算的,因爲NoReturnWithPara這個委託就是就是接收一個int和string
            NoReturnWithPara method3 = new NoReturnWithPara((id, name) => {
                Console.WriteLine($"{id} {name} {age} 學習.Net高級班");
            });
            method3.Invoke(456, "張小姐");

            //如果方法體只有一行,可以去掉大括號和分號
            NoReturnWithPara method4 = new NoReturnWithPara((id, name) => 
                Console.WriteLine($"{id} {name} {age} 學習.Net高級班")
            );
            method4.Invoke(789, "王小姐");

            //new NoReturnWithPara委託可以省掉,也是語法糖,編譯器自動加上
            NoReturnWithPara method5 = (id, name) =>
            Console.WriteLine($"{id} {name} {age} 學習.Net高級班");
            method5.Invoke(101, "楊小姐");
        }
    }
}

2、省略參數類型int和string,編譯器的語法糖,雖然沒寫,編譯時還是有的,根據委託推算的,因爲NoReturnWithPara這個委託就是就是接收一個int和string

NoReturnWithPara method3 = new NoReturnWithPara((id, name) => {
    Console.WriteLine($"{id} {name} {age} 學習.Net高級班");
});
method3.Invoke(456, "張小姐");

3、如果方法體只有一行,可以去掉大括號和分號

//如果方法體只有一行,可以去掉大括號和分號
NoReturnWithPara method4 = new NoReturnWithPara((id, name) => 
    Console.WriteLine($"{id} {name} {age} 學習.Net高級班")
);
method4.Invoke(789, "王小姐");

4、new NoReturnWithPara委託也可以省掉,也是語法糖,編譯器自動加上

//new NoReturnWithPara委託可以省掉,也是語法糖,編譯器自動加上
NoReturnWithPara method5 = (id, name) =>
Console.WriteLine($"{id} {name} {age} 學習.Net高級班");
method5.Invoke(101, "楊小姐");
  • Lamda表達式是什麼? 

1、lamda不是一個委託,因爲編譯器語法糖省略了new NoReturnWithPara,所以只是看起來像是1個委託,但是實際上從上面可以看出lamda只是實例化委託的一個參數,lamda就是個匿名方法。

2、從IL層分析,lamda是匿名方法,但是編譯的時候會分配一個名字,還會產生一個私有sealed類,這裏增加一個方法,這個方法就是跟lambda表達式一一對應的。

 

 

  • Lamda在多播委託中的特點--無法移除

lamda表達式在多播委託爲什麼加1次,減1次,爲什麼減不掉呢?多播委託裏面的lamda無法移除,雖說兩個lamda的方法內容一樣,lamda是匿名方法,但是編譯器編譯後會自動給分配方法名字,其實是2個不同的方法,所以無法移除,而Study是同1個方法,所以可以移除。

namespace LamdaHistory
{
    public class MulticastDelegate
    {
        public delegate void NoReturnWithPara(int x, string y);//聲明委託

        public  void Show()
        {
            NoReturnWithPara method = new NoReturnWithPara(this.Study);
            method += this.Study;
            method += (id, name) => { Console.WriteLine($"{id} {name} 學習.Net Core"); };

            method -= this.Study;
            method -= (id, name) => { Console.WriteLine($"{id} {name} 學習.Net Core"); };

            method.Invoke(123, "張三");
        }

        private  void Study(int id, string name)
        {
            Console.WriteLine($"{id} {name} 學習.Net Framework");
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章