VS 2017 的 C# 7.0 中引入了本地方法,本地方法是一種語法糖,容許咱們在方法內定義本地方法。更加相似於函數式語言,可是,本質上仍是基於面向對象實現的。html
先看一個示例:git
1 using static System.Console; 2 3 namespace UseLocalFunctions 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 void Add(int x, int y) 10 { 11 WriteLine($"Sum of {x} and {y}: is {x + y}"); 12 } 13 14 void Multiply(int x, int y) 15 { 16 WriteLine($"Multiply of {x} and {y} is: {x * y}"); 17 Add(30, 10); 18 } 19 20 Add(10, 30); 21 Multiply(40, 30); 22 23 ReadLine(); 24 } 25 } 26 }
在此示例中,在 Main 方法內,嵌套定義了兩個方法:Add 和 Multiply。這個方法能夠在 Main 方法內被使用。這種方法被稱爲本地方法。英文稱爲:Local function.github
使用 ILDasm 工具,能夠看到編譯以後的結果。async
這兩個本地方法被翻譯成了兩個靜態的私有方法,它只能在定義的方法內被調用。ide
本地方法的語法定義爲:函數
<modifiers: async | unsafe> <return-type> <method-name> <parameter-list>工具
方法的修飾符只有兩種:async 和 unsafe,全部的本地方法都是私有的post
本地方法也能夠帶有返回類型。若是類型用錯的話,Visual Studio 能夠給出提示。性能
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 PrintStudentMarks(101, 6 new Subject 7 { 8 SubjectName = "Math", 9 Marks = 96 10 }, new Subject 11 { 12 SubjectName = "physics", 13 Marks = 88 14 }, new Subject 15 { 16 SubjectName = "Chem", 17 Marks = 91 18 }); 19 20 ReadLine(); 21 } 22 23 public static void PrintStudentMarks(int studentId, params Subject[] subjects) 24 { 25 WriteLine($"Student Id{studentId} Total Marks: {CalculateMarks()}"); 26 WriteLine($"Student wise marks"); 27 foreach(var subject in subjects) 28 { 29 WriteLine($"Subject Name: {subject.SubjectName}\t Marks: {subject.Marks}"); 30 } 31 32 decimal CalculateMarks() 33 { 34 decimal totalMarks = 0; 35 foreach(var subject in subjects) 36 { 37 totalMarks += subject.Marks; 38 } 39 40 return totalMarks; 41 } 42 } 43 44 public class Subject 45 { 46 public string SubjectName 47 { 48 get; set; 49 } 50 51 public decimal Marks 52 { 53 get; set; 54 } 55 } 56 }
本地方法不須要維護調用堆棧,而遞歸方法須要維護調用堆棧,本地方法效率更高。下面的示例演示了兩種方法的區別。ui
注意:該示例使用了類型 BigInteger ,須要添加對程序集 System.Numeric.dll 的引用。
代碼以下。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Stopwatch watch = new Stopwatch(); 6 watch.Start(); 7 BigInteger f1 = GetFactorialUsingLocal(9000); 8 watch.Stop(); 9 WriteLine($"Using local function: {watch.ElapsedTicks}"); 10 11 watch.Reset(); 12 watch.Start(); 13 BigInteger f2 = GetFactorial(9000); 14 watch.Stop(); 15 WriteLine($"Using recursive function: {watch.ElapsedTicks}"); 16 } 17 18 private static BigInteger GetFactorialUsingLocal(int number) 19 { 20 if (number < 0) 21 throw new ArgumentException("negative number", nameof(number)); 22 else if (number == 0) 23 return 1; 24 BigInteger result = number; 25 while (number > 1) 26 { 27 Multiply(number - 1); 28 number--; 29 } 30 31 void Multiply(int x) => result *= x; 32 return result; 33 } 34 35 private static BigInteger GetFactorial(int number) 36 { 37 if (number < 0) 38 throw new ArgumentException("nagative number", nameof(number)); 39 return number == 0 ? 1 : number * GetFactorial(number - 1); 40 } 41 }
在個人機器上,結果以下:
Using local function: 181770
Using recursive function: 456602
能夠看到二者之間的性能差別。
此時,爲了傳遞 result ,在生成的代碼中,編譯器會自動作一些額外的工做。
當建立 Lambda 的時候,將會建立一個委託,這須要內存分配,由於委託是一個對象。而本地方法則不須要,它是一個真正的方法。
另外,本地方法能夠更爲有效地使用本地變量,Lambda 將變量放到類中,而本地方法可使用結構,而不使用內存分配。
這意味着調用本地方法更爲節約且可能內聯。
Lambda 也能夠實現遞歸,可是代碼醜陋,您須要先賦予 lambda 爲 null。本地方法能夠更爲天然地遞歸。
Lambda 不能使用泛型。這是由於須要賦予一個實例類型的變量。
Lambda 不能使用 yield return (以及 yield break)關鍵字,以實現 IEnumerable<T> 返回函數。本地方法能夠。