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 新特性:本地方法的更多相关文章

  1. C# 7.0 新特性2: 本地方法

    本文参考Roslyn项目中的Issue:#259. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...

  2. C# 7.0 新特性1: 基于Tuple的“多”返回值方法

    本文基于Roslyn项目中的Issue:#347 展开讨论. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: ...

  3. C# 7.0 新特性3: 模式匹配

    本文参考Roslyn项目Issue:#206,及Docs:#patterns. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# ...

  4. C# 7.0 新特性4: 返回引用

    本文参考Roslyn项目中的Issue:#118. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...

  5. c# 6.0新特性(二)

    写在前面 上篇文章介绍了c#6.0的using static,Auto Property Initializers,Index Initializers新的特性,这篇文章将把剩下的几个学习一下. 原文 ...

  6. C#6.0,C#7.0新特性

    C#6.0新特性 Auto-Property enhancements(自动属性增强) Read-only auto-properties (真正的只读属性) Auto-Property Initia ...

  7. 【c#】6.0与7.0新特性介绍记录

    c#发展史 引用地址:https://www.cnblogs.com/ShaYeBlog/p/3661424.html 6.0新特性 1.字符串拼接优化 语法格式:$”string {参数}” 解释: ...

  8. Javaweb学习笔记——(七)——————myexlipse基本使用、jdk5.0新特性及反射讲解

    1.debug调试模式: *使用这种模式,调试程序(看到程序运行停止在这一行) -显示出来行号 -双击左边,出现一个圆点,表示设置了一个断点 *使用debug as方式,运行程序 -特使是否进入到调试 ...

  9. webpack 4.0.0-beta.0 新特性介绍

    webpack 可以看做是模块打包机.它做的事情是:分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式 ...

随机推荐

  1. MongoDB-python的API手记

    -------------------python调用MongoDB------------------- 1.官方文档:http://api.mongodb.org/python/current/t ...

  2. 常用bash命令

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "Helvetica Neue"; color: #454545 } p. ...

  3. Spring Cloud Netflix多语言/非java语言支持之Spring Cloud Sidecar

    Spring Cloud Netflix多语言/非java语言支持之Spring Cloud Sidecar 前言 公司有一个调研要做,调研如何将Python语言提供的服务纳入到Spring Clou ...

  4. 聊聊并发-Java中的Copy-On-Write容器

    详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp78   聊聊并发-Java中的Copy-On-Write容器   Cop ...

  5. Python输入输出练习,运算练习,turtle初步练习

    Hello World! 简单交互(交互式,文件式)教材P19 radius=25 area=3.1415*radius*radius print(area) print('{:.2f}'.forma ...

  6. 09 Linear Regression

    线性回归假设 错误衡量/代价函数---均方误差 最小化样本内代价函数 只有满秩方阵才有逆矩阵 线性回归算法 线性回归算法是隐式迭代的 线性回归算法泛化可能的保证 线性分类是近似求解,线性回归是解析求解 ...

  7. 转:深入Java集合学习系列:HashSet的实现原理

    0.参考文献 深入Java集合学习系列:HashSet的实现原理 1.HashSet概述: HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set 的迭代顺序:特 ...

  8. bootstrap 表单+按钮+对话框

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  9. 201521123045-----《Java程序设计》第3周学习总结

    ---恢复内容开始--- 1. 本章学习总结 2. 书面作业 1. 代码阅读 public class Test1 { private int i = 1;//这行不能修改 private stati ...

  10. 201521123098 JAVA课程设计

    1.团队课程设计博客链接 http://www.cnblogs.com/agts/p/7067948.html 2.个人负责模块或任务说明 个人任务:实现初始界面中的登录.注册模块,以及数据库的连接和 ...