本文参考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. Java Se:Java Security

    Java API中有很多都使用了SecurityManager,这到底是什么玩意?最近看公司的产品的源码,也有不少SecurityManager.AccessControlContext等相关的代码, ...

  2. 用字符串模拟两个大数相加——java实现

    问题: 大数相加不能直接使用基本的int类型,因为int可以表示的整数有限,不能满足大数的要求.可以使用字符串来表示大数,模拟大数相加的过程. 思路: 1.反转两个字符串,便于从低位到高位相加和最高位 ...

  3. linux 文件系统解析及相关命令

    简介 文件系统就是分区或磁盘上的所有文件的逻辑集合. 文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件.目录.软连接及文件保护信息等都存储在其中. 不同Lin ...

  4. SCCM 客户端的修复

    1. Stopping the SMS Agent Host service (net stop ccmexec) 2. Stopping the WMI service (net stop winm ...

  5. Neutron VxLAN + Linux Bridge 环境中的网络 MTU

    1. 基础知识 1.1 MTU   一个网络接口的 MTU 是它一次所能传输的最大数据块的大小.任何超过MTU的数据块都会在传输前分成小的传输单元.MTU 有两个测量层次:网络层和链路层.比如,网络层 ...

  6. HDU 2516 取石子游戏

    Problem Description 1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出"Secon ...

  7. hdu2896 病毒侵袭 ac自动机

    地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=2896 题目: 病毒侵袭 Time Limit: 2000/1000 MS (Java/Othe ...

  8. ural Cipher Message

    Cipher Message Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Desc ...

  9. StringBuffer和StringBuilder的区别

    StringBuffer和StringBuilder的区别 StringBuffer与StringBuilder就不一样了,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在 ...

  10. [No00000F]Excel快捷键大全 Excel2013/2010/2007/2003常用快捷键大全

    一个软件最大的用处是提高工作效率,衡量一个软件的好坏,除了是否出名之外,最主就是能否让一个新手更快的学会这个软件和提高工作速度.就拿Excel表格来说吧,平常办公中我们经常会用它来制作表格,统计数据或 ...