本文参考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. 用wget扒站时遇到电信劫持

    今天用wget扒下来一个html template的站. 挂在自己机器上后随便点什么,都出电信广告.仔细检查,我勒个去... 扒站过程中,刚好被电信打了劫,看看它给我下载下来的bootstrap.mi ...

  2. linux中send函数MSG_NOSIGNAL异常消息

    最近2周在做ineedle的国舜项目扩展,需要使用socket的tcp连接向对方发送消息,当然需求很简单,只是按照对方要求发送指定格式的消息,程序结构也非常的简单,一对多的client/server模 ...

  3. mysql优化之索引篇

    对mysql优化是一个综合性的技术,主要包括 a: 表的设计合理化(符合3NF) b: 添加适当索引(index) [四种: 普通索引.主键索引.唯一索引unique.全文索引] c: 分表技术(水平 ...

  4. 没学过CSS等前端的我,也想美化一下自己的博客

    随便说几句: 自己一直学的都是 C++和 Java 以及 Python语言,根本不懂高大上的 CSS 和 著名的 HTML5.感觉那些能自己设计那么漂亮的博客的朋友都好厉害.可以自己加上博客公告栏的小 ...

  5. CURL使用方法详解

    php采集神器CURL使用方法详解 作者:佚名  更新时间:2016-10-21   对于做过数据采集的人来说,cURL一定不会陌生.虽然在PHP中有file_get_contents函数可以获取远程 ...

  6. Redhat下如何搭建NFS

    环境: OS:Red Hat Linux As 5 服务器ip:192.168.50.199客户端ip:192.168.50.200 1.服务器上创建共享目录同时修改权限mkdir /bak1/nfs ...

  7. 大话设计模式C++版——抽象工厂模式

    前面说过,简单工厂模式是最基础的一种设计模式,那以工厂命名的设计模式就是23种设计模式中最多的一种,他们一脉相承,一步一步进化而来,这里就是其中的最后一种——抽象工厂模式(Abstract Facto ...

  8. Java开发之JSP行为

    一.Java Bean行文 1.重点说明 Java Bean行为是一组与Java Bean相关的行为,包括useBean行为.setProperty行为.getProperty行为等.Java Bea ...

  9. ATM模拟程序

    一个很简单的ATM模拟程序 #include <stdio.h> void chaxun(int a3){ int b; b=a3; printf("您的余额为:%d\n&quo ...

  10. 批处理文件指定jre路径启动java桌面应用程序

    应用场景: 我开发了一个应用程序,并连同jre一起刻成光盘,提供给用户,用户直接双击批处理文件即可运行,而不需要自己额外装jre. 目录组织结构如下: client |-images |-jre |- ...