本文参考Roslyn项目中的Issue:#259.

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

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

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

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

简而言之,【本地方法】就是在方法体内部定义一个方法

其实咋眼一看,这个新特新并没有什么新意,因为目前大量C#的项目中,都可以使用delegate或基于delegate变形的各种方案(lambda, Fun<*>, Action, Action<*> ...)。

但是请仔细推敲一下,方法体内部delegate,是否真的那么完美无缺……

目前的C#

我们看一下,通常方法内部设置子逻辑单元的做法。

 public void Bar()
{
var arr= new int[] { , ,, };
Func<int, string> handler = i => $"当前值是:{i}。";
foreach (var i in arr)
{
Console.WriteLine(handler(i));
}
}

看起来有什么问题吗?当然,很多。

  1. 首先,handler是无法进行递归调用的,看下面的代码。

 public int Bar(int n)
{
if (n < ) throw new ArgumentException();
Func<int, int> handler = n => {
if (n == ) return ;
return n * handler(n - 1);
};
return handler(n);
}

  这时handler(n-1) 的调用会报错(Use of unassigned local variable 'handler'),原因是handler还未被赋值。通常,这种问题我们会尝试用一种非常难看的做法变通解决:

 Func<int, int> handler = null;
handler = n =>{
if (n == ) return ;
return n * handler(n - );
};

  咳咳咳,不多说了,心里一万只羊驼狂奔而过。

  2. 其次,Lambda表达式的使用,非常有局限,它不允许在参数中添加行为修饰 out, ref, params, 以及可选参数,均不能在Lambda表达式的参数表中出现。参数无法使用泛型。

  3. 分配了一个委托对象来指向函数,为了能够在Lambda表达式中访问本地变量,会为其分配一个新的对象,间接的增加了GC的压力。

说到这里,可能有的童鞋会自然的想到更原始的解决方案,在外部声明一个私有函数,就不会存在以上一系列的问题。

 class Foo
{
public void Bar(int[] arr)
{
foreach(var i in arr)
{
Console.WriteLine(Handler(i));
}
} private string Handler(int i) => $"当前值是:{i}";
}

这的确是一种简单粗暴的解决方案,但是依然存在一些小问题,一个仅在Bar方法中有引用的方法,逻辑上也没必要暴露给this的其他成员。这种做法其实是结构上的一种不合理。

本地方法(Local Function)

在C#7.0中,允许代码直接在一个方法体(方法,构造,属性的Getter和Setter)里声明并调用子方法。

废话不说,上代码:

 public void Bar(int[] arr)
{
var length = arr.Length;
string Length() {
return $"length is {length}";
}
//或:
//string Length() => $"length is {length}";
Length();
}

上面例子中的Length(),在编译后会转化成当前类的私有成员方法(IL: this.<Bar>g__Length(): string()),但由于在C#语言层面做出了限制,只被允许在Bar方法中访问。

由于对this而言,是以类似匿名方法的形态存在,所以,在当前类中仍然可以定义同名且同样声明的成员方法,从所在的方法体中调用,会执行本地方法。

Okay,话说回来,由于它的本质成员方法,所以它可以避免 [委托 / Lambda表达式] 的种种限制,可以异步,可用泛型,可用out, ref, param, 可以yield, 特性参数, 等等。。

来个例子:

 class Foo
{
public IEnumerable<T> Bar<T>(params T[] items)
{
if (items == null) throw new ArgumentException(nameof(items)); IEnumerable<T2> Enumerate<T2> ([CallerMemberName] T2[] array) //使用泛型及特性参数
{
//本地方法逻辑
foreach (var item in array)
{
yield return item; //使用迭代器
}
} return Enumerate<T>(items); //调用本地方法
//return this.Enumerate<T>(items); //调用成员方法
} IEnumerable<T2> Enumerate<T2>([CallerMemberName] T2[] array)
{
//成员方法逻辑
}
}

总结

这个feature可以看出,C#在朝着函数式语言谨慎的调整。回想起很多人在首次接触代码的懵懂期,经常犯一种比较低级的错误,傻傻的尝试在Main方法中写函数声明,现在看来,那才是最直接的思维逻辑。

本文链接:http://www.cnblogs.com/ylvict/p/5579350.html  (转载请注明)

目前(2016年6月)C#7.0还未正式发布,大家如果想体验部分特性,可以去下载VS15预览版,最终发布的语法可能和本文中提及的有所不同,最新动态请大家关注Roslyn项目。

C# 7.0 新特性2: 本地方法的更多相关文章

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

    C# 7.0:本地方法 VS 2017 的 C# 7.0 中引入了本地方法,本地方法是一种语法糖,允许我们在方法内定义本地方法.更加类似于函数式语言,但是,本质上还是基于面向对象实现的. 1. 本地方 ...

  2. C#3.0新特性之扩展方法介绍

    C#3.0扩展方法是给现有类型添加一个方法.现在类型即可是基本数据类型(如int,String等),也可以是自己定义的类.以下是引用片段: //Demo--1 //扩展基本类型 namespace T ...

  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: ...

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

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

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

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

  6. c# 6.0新特性(二)

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

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

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

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

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

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

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

随机推荐

  1. sed实例精解--例说sed完整版

    原文地址:sed实例精解--例说sed完整版 作者:xiaozhenggang 最近在学习shell,怕学了后面忘了前面的就把学习和实验的过程记录下来了.这里是关于sed的,前面有三四篇分开的,现在都 ...

  2. flume架构初接触

    flume优点 1.存储数据到任何中央数据库 2.进入数据速率大于写出速率,可以起到缓存作用,保证流的平稳 3.提供文本式路由 4.支持事务 5.可靠.容错.可伸缩.可定制.可管理 put的缺点 1. ...

  3. java 中的volatile

    本博客摘录自   http://www.infoq.com/cn/articles/java-memory-model-4/ 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解 ...

  4. 今天说一下 tablesample 这个东西

    TableSample 平时用得少,基本上就是用于表里面抽样数据来看的. 用法如下 SELECT * FROM tbname TABLESAMPLE SYSTEM (N PERCENT/M Rows) ...

  5. InnoDB源码分析--事务日志(一)

    原创文章,转载请注明原文链接(http://www.cnblogs.com/wingsless/p/5705314.html) 在之前的文章<InnoDB的WAL方式学习>(http:// ...

  6. 烂泥:【解决】VMware Workstation中安装ESXI5.0双网卡问题

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 由于需要做ESXI相关的实验,所以就在自己的机器上利用VM虚拟ESXI进行实验.因为此次实验是需要两块网卡的,所以就在创建ESXI虚拟机时添加了两块网卡 ...

  7. Java文件选择对话框(文件选择器JFileChooser)的使用:以一个文件加密器为例

    文件加密器,操作过程肯定涉及到文件选择器的使用,所以这里以文件加密器为例.下例为我自己写的一个文件加密器,没什么特别的加密算法,只为演示文件选择器JFileChooser的使用. 加密器界面如图: 项 ...

  8. 探究C语言中的前++和后++

    小波带您探究c语言中的前++与后++: 欢迎吐槽,欢迎加QQ463431476. 欢迎关注!  现在来探究: 咱们先看第一个 i被赋值0,i++(后++)并没有输出1.   现在i被赋值0,++i,也 ...

  9. MT7620a openwrt barrier_breaker编译后wan口dhcp无法获得地址

    前言 我司准备使用openwrt barrier_breaker版本做二次开发.在烧入固件后发现wan口,dhcp无法获得地址.经如下修改后,mt7620a的路由器可以正常获得地址. 修改dts文件 ...

  10. Win8 忘记密码 解决办法【在E450c实测有效】

      工具/原料 已经刻录通用PE工具箱的U盘 方法/步骤 1 首先来看一下,问题产生的状况.出现登陆界面,由于密码忘记,怎么输入密码,老是提示密码错误 2 接下来,按住Shift,电脑关机重启,也就是 ...