C# 7.0 新特性:本地方法
C# 7.0:本地方法
VS 2017 的 C# 7.0 中引入了本地方法,本地方法是一种语法糖,允许我们在方法内定义本地方法。更加类似于函数式语言,但是,本质上还是基于面向对象实现的。
1. 本地方法
先看一个示例:
- using static System.Console;
- namespace UseLocalFunctions
- {
- class Program
- {
- static void Main(string[] args)
- {
- void Add(int x, int y)
- {
- WriteLine($"Sum of {x} and {y}: is {x + y}");
- }
- void Multiply(int x, int y)
- {
- WriteLine($"Multiply of {x} and {y} is: {x * y}");
- Add(, );
- }
- Add(, );
- Multiply(, );
- ReadLine();
- }
- }
- }
在此示例中,在 Main 方法内,嵌套定义了两个方法:Add 和 Multiply。这个方法可以在 Main 方法内被使用。这种方法被称为本地方法。英文称为:Local function.
使用 ILDasm 工具,可以看到编译之后的结果。
这两个本地方法被翻译成了两个静态的私有方法,它只能在定义的方法内被调用。
本地方法的语法定义为:
<modifiers: async | unsafe> <return-type> <method-name> <parameter-list>
方法的修饰符只有两种:async 和 unsafe,所有的本地方法都是私有的
- 如果您使用了 private 修饰,会收到 编译器的错误提示:error CS0106, "The modifier 'static' is not valid for this item."
- 如果您使用了 static,会收到编译器的错误提示:error CS0106, "The modifier 'static' is not valid for this item."
2. 带有返回类型的本地方法
本地方法也可以带有返回类型。如果类型用错的话,Visual Studio 可以给出提示。
- class Program
- {
- static void Main(string[] args)
- {
- PrintStudentMarks(,
- new Subject
- {
- SubjectName = "Math",
- Marks =
- }, new Subject
- {
- SubjectName = "physics",
- Marks =
- }, new Subject
- {
- SubjectName = "Chem",
- Marks =
- });
- ReadLine();
- }
- public static void PrintStudentMarks(int studentId, params Subject[] subjects)
- {
- WriteLine($"Student Id{studentId} Total Marks: {CalculateMarks()}");
- WriteLine($"Student wise marks");
- foreach(var subject in subjects)
- {
- WriteLine($"Subject Name: {subject.SubjectName}\t Marks: {subject.Marks}");
- }
- decimal CalculateMarks()
- {
- decimal totalMarks = ;
- foreach(var subject in subjects)
- {
- totalMarks += subject.Marks;
- }
- return totalMarks;
- }
- }
- public class Subject
- {
- public string SubjectName
- {
- get; set;
- }
- public decimal Marks
- {
- get; set;
- }
- }
- }
3. 使用本地方法实现递归
本地方法不需要维护调用堆栈,而递归方法需要维护调用堆栈,本地方法效率更高。下面的示例演示了两种方法的区别。
注意:该示例使用了类型 BigInteger ,需要添加对程序集 System.Numeric.dll 的引用。
代码如下。
- class Program
- {
- static void Main(string[] args)
- {
- Stopwatch watch = new Stopwatch();
- watch.Start();
- BigInteger f1 = GetFactorialUsingLocal();
- watch.Stop();
- WriteLine($"Using local function: {watch.ElapsedTicks}");
- watch.Reset();
- watch.Start();
- BigInteger f2 = GetFactorial();
- watch.Stop();
- WriteLine($"Using recursive function: {watch.ElapsedTicks}");
- }
- private static BigInteger GetFactorialUsingLocal(int number)
- {
- if (number < )
- throw new ArgumentException("negative number", nameof(number));
- else if (number == )
- return ;
- BigInteger result = number;
- while (number > )
- {
- Multiply(number - );
- number--;
- }
- void Multiply(int x) => result *= x;
- return result;
- }
- private static BigInteger GetFactorial(int number)
- {
- if (number < )
- throw new ArgumentException("nagative number", nameof(number));
- return number == ? : number * GetFactorial(number - );
- }
- }
在我的机器上,结果如下:
Using local function: 181770
Using recursive function: 456602
可以看到两者之间的性能差异。
此时,为了传递 result ,在生成的代码中,编译器会自动做一些额外的工作。
4. 本地方法与 Lambda 的比较
1. 性能
当创建 Lambda 的时候,将会创建一个委托,这需要内存分配,因为委托是一个对象。而本地方法则不需要,它是一个真正的方法。
另外,本地方法可以更为有效地使用本地变量,Lambda 将变量放到类中,而本地方法可以使用结构,而不使用内存分配。
这意味着调用本地方法更为节约且可能内联。
2. 本地方法可以递归
Lambda 也可以实现递归,但是代码丑陋,您需要先赋予 lambda 为 null。本地方法可以更为自然地递归。
3. 本地方法可以使用泛型
Lambda 不能使用泛型。这是因为需要赋予一个实例类型的变量。
4. 本地方法可以实现迭代器
Lambda 不能使用 yield return (以及 yield break)关键字,以实现 IEnumerable<T> 返回函数。本地方法可以。
5. 本地方法更为易读
5. 其它资源:
C# 7.0 新特性:本地方法的更多相关文章
- C# 7.0 新特性2: 本地方法
本文参考Roslyn项目中的Issue:#259. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...
- C# 7.0 新特性1: 基于Tuple的“多”返回值方法
本文基于Roslyn项目中的Issue:#347 展开讨论. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: ...
- C# 7.0 新特性3: 模式匹配
本文参考Roslyn项目Issue:#206,及Docs:#patterns. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# ...
- C# 7.0 新特性4: 返回引用
本文参考Roslyn项目中的Issue:#118. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...
- c# 6.0新特性(二)
写在前面 上篇文章介绍了c#6.0的using static,Auto Property Initializers,Index Initializers新的特性,这篇文章将把剩下的几个学习一下. 原文 ...
- C#6.0,C#7.0新特性
C#6.0新特性 Auto-Property enhancements(自动属性增强) Read-only auto-properties (真正的只读属性) Auto-Property Initia ...
- 【c#】6.0与7.0新特性介绍记录
c#发展史 引用地址:https://www.cnblogs.com/ShaYeBlog/p/3661424.html 6.0新特性 1.字符串拼接优化 语法格式:$”string {参数}” 解释: ...
- Javaweb学习笔记——(七)——————myexlipse基本使用、jdk5.0新特性及反射讲解
1.debug调试模式: *使用这种模式,调试程序(看到程序运行停止在这一行) -显示出来行号 -双击左边,出现一个圆点,表示设置了一个断点 *使用debug as方式,运行程序 -特使是否进入到调试 ...
- webpack 4.0.0-beta.0 新特性介绍
webpack 可以看做是模块打包机.它做的事情是:分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式 ...
随机推荐
- 比较三个 CSS 预处理器:Sass、LESS 和 Stylus(下)
五.Mixins (混入) Mixins 有点像是函数或者是宏,当你某段 CSS 经常需要在多个元素中使用时,你可以为这些共用的 CSS 定义一个 Mixin,然后你只需要在需要引用这些 CSS 地方 ...
- ORACLE ROWNUM解析
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp53 [align=middle;" align="le ...
- 第1阶段——uboot分析之通过nand命令读内核(8)
本节主要学习: 详细分析UBOOT中"bootcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0" 怎么实现nand命令读 ...
- 解决Android Studio中Refreshing gradle project时间过长的最简单方法
Refreshing gradle project往往出现在Gradle出现更新,需要从墙外的网重新拖下来的前提下.具体可以查看以下文件:/path/to/project/gradle/wrapper ...
- [js高手之路]Node.js实现简易的爬虫-抓取博客文章列表信息
抓取目标:就是我自己的博客:http://www.cnblogs.com/ghostwu/ 需要实现的功能: 抓取文章标题,超链接,文章摘要,发布时间 需要用到的库: node.js自带的http库 ...
- Java的构造器
初始化和清理是涉及安全的两个问题.C++和Java都引入了构造器(constructor)的概念,这是一个在创建对象时被自动调用的特殊方法. 可以假想为编写的每个类都定义一个initialize()方 ...
- php的mysql语句里变量加不加单引号问题
第一种[{$_GET['id']}加不加单引号都能正常执行没问题] $sql = "select * from `news` where `id` = {$_GET['id']}" ...
- 转:【Java集合源码剖析】Vector源码剖析
转载请注明出处:http://blog.csdn.net/ns_code/article/details/35793865 Vector简介 Vector也是基于数组实现的,是一个动态数组,其容量 ...
- 大家一起来找茬(BUG)
大家一起来找茬(BUG) ----------目录---------- 一.上手体验 1.主界面 2.功能 二.程序的 BUG 三.必应词典的 BUG 1."每日一句"里的句子不能 ...
- 201521123110 《Java程序设计》第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. private不对用户公开进行修改,public用户可以进行修改.代码可以进行继承,即子类继 ...