2天时间,聊今年最热的 Agent、上下文工程、AI 产品创新等话题。2025 年最后一场~ 了解详情
写点什么

C# 7 特性预览

  • 2016-04-06
  • 本文字数:3009 字

    阅读完需:约 10 分钟

在过去一年间,我们为读者展示了多个已考虑加入C# 7 中的特性。在最近发布的Visual Studio 15 预览版中,微软决定为用户展现这些特性,使其成为C# 7 最终发布的一部分。

元组值类型

.NET 提供了一个元组(Tuple)类型,但具体在C#中使用时却存在着各种各样的问题。由于元组类型是一个引用类型,因此在一些对于性能相当敏感的代码中,你很可能会避免因使用它而造成GC 的开销。同时,元组类型是不可变的,虽然这使跨线程共享变得更安全,但也意味着每次进行变更都必须分配一个新的对象。

为了应对这一问题,C# 7 将提供一个值类型的元组。这是一个可变类型,对那些重视性能的代码来说,这种方式将更为高效。同时,作为值类型,它在每次进行分配时都会生成一个拷贝,因此几乎没有产生多线程问题的风险。

你可以通过以下语法创建一个元组:

复制代码
var result = (5, 20);

你也可以选择对元组中的值进行命名,这一点并不是必须的,只是让代码具有更好的可读性。

复制代码
var result = (count: 5, sum: 20);

你可能会想,“很棒的特性,但我自己也能写得出来”。但下一个特性才是重头戏。

多返回值

在类C 风格的语言中,要在一个函数中返回两个值始终是一件麻烦事。你只能选择将结果封装成某种结构,或是使用输出参数。与许多函数式编程语言一样,C#选择了第一种方式为你提供这一特性:

复制代码
(int, int) Tally (IEnumerable<int> list)

可以看到,在这里使用泛用的元组有一个基本问题:我们将无从得知每个字段的作用。因此,C#选择通过一个编译器花招对结果进行命名:

复制代码
(int Count, int Sum) Tally (IEnumerable<int> list)

我们在此需要强调一点:C#并没有生成一个新的匿名类型,你所获得的仍旧是一个元组,但编译器将假设它的属性为 Count 和 Sum,而不是 Item1 和 Item2。所以,以下代码行的作用都是等价的:

复制代码
var result = Tally(list);
Console.WriteLine(result.Item1);
Console.WriteLine(result.Count);

请注意一点,我们现在还不具备多赋值语法,如果这种语法最终实现,那么它的用法可能是这样的:

复制代码
(count, sum) = Tally(list);

除了提供简单的功能性函数之外,多返回值的实用性还体现在异步代码的编写上,因为在 async 函数中是不允许使用 out 参数的。

模式匹配:改进的 Switch 语法块

VB 与函数式程序员对于 C#抱怨得最多的一点就是 C#中的 switch 语句功能十分有限。VB 开发者希望能够进行范围匹配,而习惯了 F#或 Haskell 的开发者则希望能够使用分解式的模式匹配。C#打算同时提供这两种特性。

在对类型进行模式匹配时,你可以创建一个变量以保存转型的结果。举例来说,在对一个 System.Object 使用 switch 语句时,你可以编写以下代码:

复制代码
case int x:

如果该对象是数值类型,则变量 x 将得以赋值。否则的话,程序将按从上至下的顺序检查下一个 case 语句块。如果你想更具体地进行匹配,还可以使用范围检查:

复制代码
case int x when x > 0:
case int y:

在这个示例中,如果该对象是正整数,则 x 代码块将被执行。如果对象是 0 或负整数,而 y 代码块将被执行。

如果需要检查 null 值,则只需使用以下语法:

复制代码
case null;

模式匹配:分解

目前为止,我们仅仅展示了某种对 VB 中已有的特性所做的增量式改进,而模式匹配真正的强大之处在于分解,它可以将某个对象完全拆开,考虑一下以下语法:

复制代码
if (person is Professor {Subject is var s, FirstName is "Scott"})

这段代码完成了两件事:

  1. 它创建了一个本地变量 s,将其赋值为 ((Professor)person).Subject。
  2. 它执行了一次相等性检查 ((Professor)person).FirstName == “Scott”。

如果将其用 C# 6 代码改写则是这样:

复制代码
var temp = person as Professor;
if (temp != null && temp.FirstName == "Scott")
{
var s = temp.Subject

在最终发布中,我们预计能够同时看到对 switch 语句块的这两种改进。

引用返回

对于大数据结构进行引用传递比起值传递要快得多,因为后者需要对整个结构进行拷贝。与之类似,返回一个大数据结构的引用一样能够提升速度。

在类似于 C 这样的语言中,可以通过指针返回某个结构的引用。这种方式会带来一个常见的问题,即指针所指向的内存可能会因为某种原因而已经被回收了。

C#通过使用引用的方式回避这一问题,引用本身是一个附加了规则的指针。最重要的一条规则是,你不能够返回某个本地变量的引用。如果你尝试这样做,那么该变量所引用的栈信息在函数返回时就已经变得不可访问了。

在微软的展示代码中,它所返回的引用指向一个数组中的某个结构。由于它实质上是指向数组中某个元素的指针,因此随后可以对数组本身进行修改。举例来说:

复制代码
var x = ref FirstElement(myArray)
x = 5; //MyArray[0] now equals 5

这一语法的用例是对性能高度敏感的代码,在大多数应用中都无需使用这一特性。

二进制字面值(Binary Literals)

此次发布还引入了一个小特性,即二进制字面值。这一语法只是一个简单的前缀而已,例如 5 可以表示为“0b0101”。这一特性的主要用例是设置基于 flag 的枚举,以及创建位掩码(bitmask),以用于与 C 风格语言的互操作。

本地函数

本地函数是指在另一个函数中所定义的函数。第一眼看来,本地函数似乎只是比匿名函数稍好的一种语法。但它实际上还存在几个优点:

  • 首先,你无需为其分配一个委托以保存该函数。这不仅减少了内存压力,同时还允许编译器对该函数进行内联操作。
  • 其次,在创建闭包时,也无需为其分配一个对象,因为它能够直接访问本地变量。这一点同样能够改善性能,因为它也减少了 GC 的压力。

按照第二条规则推算,你将无法创建一个指向本地函数的委托。这一点对于代码的组织其实是一个优点,因为你无需创建独立的函数,并且将现有函数的状态作为显式的参数进行传递。

部分类的改进

最后演示的特性是一种处理部分类的新方式。在过去,部分类的应用是基于代码生成优先的概念而出现的。所生成的代码将包含一系列部分方法,开发者可以选择实现这些方法,以调整类的行为。

通过新的“replace”语法,开发者就多了一种新选择,能够以最直接的方式编写代码,随后再引入代码生成器,并重写这些方法。以下将通过一个简单的示例表现开发者的代码编写方式:

复制代码
public string FirstName {get; set;}

简单又清晰,但完全不符合 XAML 风格应用的写法。因此,代码生成器将生成如下代码:

复制代码
private string m_FirstName;
static readonly PropertyChangedEventArgs s_FirstName_EventArgs =new PropertyChangedEventArgs("FirstName")
replace public string FirstName {
get {
return m_FirstName;
}
set {
if (m_FirstName == value)
return;
m_FirstName = value;
PropertyChanged?.Invoke(this, m_FirstName_EventArg);
}

通过“replace”关键字,所生成的代码将直接替换手写的代码,添加所缺失的功能。在这个示例中,我们甚至还能够处理一些开发者经常会忽略的麻烦的部分,例如对 EventArgs 对象进行缓存。

虽然这个官方示例仅用于属性变更通知,但这一技术还可用于各种“面向切面编程(AOP)”的场景,例如在代码中注入日志记录、安全检查、参数校验以及其他各种繁琐的样板式代码。

如果读者想实际了解一下这些特性,可以观赏 Channel 9 中的视频“ The Future of C#”。

查看英文原文 C# 7 Features Previewed

【微软开发工具】 Visual Studio Community 提供了供个人开发者、开放源代码项目、学术研究、教育和小型专业团队的免费使用,并根据具体需求来创建面向 Windows、Android 和 iOS 的新式 App、WebApp 和云服务。

2016-04-06 19:005840
用户头像

发布了 428 篇内容, 共 200.2 次阅读, 收获喜欢 39 次。

关注

评论

发布
暂无评论
发现更多内容

世界读书日 | 开发者必读书单重磅来袭,华为云DTSE专家天团力荐

华为云开发者联盟

华为云 华为云开发者联盟 企业号2024年4月PK榜 世界读书日 开发者必读书单

lerna-lite 轻量化 monorepo 管理利器

小鑫同学

面试不会算法和数据结构,经典面试题讲解来了!

霍格沃兹测试开发学社

MES管理系统与其他系统的集成

万界星空科技

数字化转型 系统集成 mes 万界星空科技

出海不出局 | 小游戏引爆高线市场,新竞争态势下的应用出海攻略

融云 RongCloud

金三银四 面试准备 数据结构面试题,编程与算法经典面试题

测试人

面试 软件测试 求职

第六届科技无障碍发展大会(2024TADC)

信息无障碍研究会

驼峰与下划线在python中转化

麦兜

玩转云端| 拥有HBlock这项“存储盘活绝技”,数据中心也能“热辣瘦身”!

天翼云开发者社区

云计算 存储 数据中心 集群

Ceph的crush算法与一致性hash对比介绍

天翼云开发者社区

云计算 存储 云服务

Prompt工程师压箱底绝活——Prompt的基本组成部分、格式化输出与应用构建

百度Geek说

企业号 4 月 PK 榜 Prompt

利用jd.item_get API获取商品信息,打造可读性强的商品介绍

技术冰糖葫芦

API 接口 API 文档 pinduoduo API

认识一下JavaScrip中的元编程

华为云开发者联盟

开发 华为云 华为云开发者联盟 企业号2024年4月PK榜

软件测试学习笔记丨Selenium网页frame

测试人

软件测试

如何通过二维码追踪物品流转情况?添加这个组件即可

草料二维码

二维码 草料二维码

Stable Diffusion中的常用术语解析

程序那些事

人工智能 程序那些事 openai

卡片式笔记系统BYEAP介绍

zhumingwu

信创国产化替换势在必行,“重复造车轮”应避免

FinFish

国产化 小程序容器 信创化软件 信创化

文心中国行走进成都!4月24日一起把握大模型时代的产业新机遇

飞桨PaddlePaddle

百度 BAIDU 百度飞桨 文心大模型 文心中国行

LLaMA 2语言大模型的微调策略:LoRA与全参数选择

百度开发者中心

人工智能 大模型 llama2

GLM国产大模型训练加速:高效性能与成本优化的实践

百度开发者中心

人工智能 深度学习 大模型

仓储管理解决方案:混合低代码与定制开发,实现灵活性与效率的完美结合

天津汇柏科技有限公司

低代码开发 软件开发定制 仓储系统

Apifox 最新功能更新:OAuth 2.0 鉴权、多分支Mock及更多

Apifox

程序员 前端 后端 Apifox

MES系统解决方案,MES系统主要能解决什么问题

万界星空科技

数字化 生产管理系统 mes 万界星空科技 车间管理

C# 7特性预览_.NET_Jonathan Allen_InfoQ精选文章