C# 6.0 新特性 (三)
主构造函数
自动属性初始化表达式尤其适合与主构造函数结合使用。主构造函数为降低常见对象模式的繁琐程度提供了一种方法。此功能自五月以来已显著改进。更新包括:
- 主构造函数的可选实现主体:这将支持此前不受支持的主构造函数参数验证和初始化等。
- 取消字段参数:通过主构造函数参数对字段进行声明。(不将此功能按照已定义方式推出是正确的决定,因为它不再按照 C# 之前矛盾的方式强制遵循特定命名约定。)
- 支持表达式主体函数和属性(本文稍后将进行讨论)。
随着 Web 服务、多层应用程序、数据服务、Web API、JSON 及类似技术的普遍使用,类的一个普遍形式是数据传输对象 (DTO)。DTO 通常不会实现太多功能,而是专注于使数据存储简单化。它对于简单性的关注使得主构造函数极具新引力。例如,请看本示例中所示的固定 Pair 数据结构:
struct Pair<T>(T first, T second)
{
public T First { get; } = first;
public T Second { get; } = second;
// Equality operator ...
}
构造函数定义 Pair(string first, string second) 已合并到类声明中。这会将构造函数参数指定为 first 和 second(均为类型 T)。属性初始化表达式中也引用了这些参数,并将参数分配给其对应的属性。当您发现此类定义的简单性、对不变性的支持以及必不可少的构造函数(所有属性/字段的初始化表达式)时,您将会了解到它是如何帮助您正确编写代码的。这将导致先前需要不必要的详细级别的常见模式得到显著改进。
主构造函数主体指定对主构造函数执行的操作。这将有助于您在主构造函数上实现通常在构造函数上可以实现的等同功能。例如,改进 Pair<T> 数据结构的可靠性的下一个步骤可能是提供属性验证。此类验证可以确保 Pair.First 的 null 值将无效。现在,CTP3 包括一个主构造函数主体(未声明的构造函数主体),如图 4 中所示。
实现主构造函数主体 struct Pair<T>(T first, T second)
{
{
if (first == null) throw new ArgumentNullException("first");
First = first; // NOTE: Not working in CTP3
}
public T First { get; }; // NOTE: Results in compile error for CTP3
public T Second { get; } = second;
public int CompareTo(T first, T second)
{
return first.CompareTo(First) + second.CompareTo(Second);
}
// Equality operator ...
}
为清晰起见,我将主构造函数主体置于类的第一个成员中。但这不是 C# 所要求的。主构造函数主体可以按与其他类成员相关的任意顺序显示。
只读属性的另一个功能尽管在 CTP3 中没有发挥作用,但您可以从构造函数内直接分配这些属性(例如,First = first)。这不仅仅限于主构造函数,而且还适用于所有构造函数成员。
支持自动属性初始化表达式的一个有趣的结果是,它解决了早期版本中出现的需要显式字段声明的多种情况。它没有解决一个最明显的问题,即需要对 setter 进行验证的情况。另一方面,几乎已不需要声明只读字段。现在,无论何时声明只读字段,只要需要该封装级别,您都可以将只读自动属性声明为私有。
CompareTo 方法具有参数 first 和 second,这好像与主构造函数的参数名称重复。由于主构造函数名称在自动属性初始化表达式作用域内,因此,first 和 second 似乎并不明确。幸运的是,实际情况并非如此。作用域规则将依据不同维度而定,而您之前在 C# 中并未看到。
在 C# 6.0 之前,作用域始终由代码内的变量声明放置来确定。参数在其帮助声明的方法中绑定,字段在类中绑定,在 if 语句中声明的变量由 if 语句条件主体绑定。
相比之下,主构造函数参数则由时间来绑定。主构造函数参数仅在执行主构造函数时为“活动”状态。此时间范围在主构造函数主体的情况中很明显。可能对于自动属性初始化表达式的情况不太明显。
但是,与作为 C# 1.0+ 中的类初始化表达式的一部分执行的转换为语句的字段初始化表达式类似,自动属性初始化表达式也通过同样的方式实现。换言之,主构造函数参数的作用域与类初始化表达式和主构造函数主体的生命周期绑定。在自动属性初始化表达式或主构造函数主体外部对主构造函数参数进行任何引用都将产生编译错误。
还有其他几个与主构造函数相关的概念需要牢记。只有主构造函数可以调用基构造函数。您可以使用主构造函数声明后跟的基本(上下文)关键字执行此操作:
class UsbConnectionException(
string message, Exception innerException, HidDeviceInfo hidDeviceInfo):
Exception (message, innerException)
{
public HidDeviceInfo HidDeviceInfo { get; } = hidDeviceInfo;
}
如果指定其他构造函数,则构造函数调用链必须最后调用主构造函数。这意味着主构造函数不能具有此初始化表达式。假定主构造函数也不是默认构造函数,所有其他构造函数必须具有这些初始化表达式:
public class Patent(string title, string yearOfPublication)
{
public Patent(string title, string yearOfPublication,
IEnumerable<string> inventors)
...this(title, yearOfPublication)
{
Inventors.AddRange(inventors);
}
}
希望这些示例有助于展示主构造函数简化了 C#。通过主构造函数,还有机会以简单的方式来执行简单的任务,而不是以复杂的方式来执行简单的任务。它偶尔也会让类包含多个主构造函数和调用链,致使代码不易于阅读。如果您遇到主构造函数语法使代码看起来更为复杂而不是简化代码的情况,那么请不要使用主构造函数。对于 C# 6.0 的所有增强功能,如果您有不喜欢的功能,或某个功能使您的代码不易于阅读,请不要使用该功能。
表达式主体函数和表达式属性
表达式主体函数是 C# 6.0 中的另一个语法精简形式。有一些函数不包括语句体,而是以函数声明后跟表达式的形式来实现。
例如,可以这样向 Pair<T> 类添加 ToString 方法的重写:
public override string ToString() => string.Format("{0}, {1}", First, Second);
表达式主体函数没有什么彻底更改。和 C# 6.0 中的大部分功能一样,它们旨在提供简化的语法,用于实现简单的情况。当然,表达式的返回类型必须与函数声明中定义的返回类型相匹配。在这种情况下,ToString 将返回一个字符串,这同函数实现表达式返回的结果一样。返回 void 或 Task 的方法应通过同样不会返回任何结果的表达式实现。
表达式主体简化不仅仅限于函数,您还可以使用表达式实现只读(仅包含 getter)属性——表达式属性。例如,可以将 Text 成员添加到 FingerPrint 类:
public string Text =>
string.Format("{0}: {1} - {2} ({3})", TimeStamp, Process, Config, User);
其他功能
有一些功能不再计划针对 C# 6.0 实现:
- 索引属性运算符 ($) 不再可用,并且不针对 C# 6.0 实现。
- 尽管索引成员语法预期在 C# 6.0 的更高版本中回归,但它在 CTP3 中不起作用:
var cppHelloWorldProgram = new Dictionary<int, string>
{
[] = "main() {",
[] = " printf(\"hello, world\")",
[] = "}"
};主构造函数中的字段参数不再属于 C# 6.0。
- 二进制数字文本和数字文本中的数字分隔符 (‘_’) 在正式发布之前尚不确定。
原文出处:http://msdn.microsoft.com/zh-cn/magazine/dn802602.aspx
C# 6.0 新特性 (三)的更多相关文章
- C++2.0新特性(三)——<=default,=delete、alias(别名)、noexcept、override、final、以及和const对比>
一.=default,=delete 1.首先我们要回顾一下类默认函数的概念: C++中,当我们设计与编写一个类时,若不显著申明,则类会默认为我们提供如下几个函数: (1)构造函数(A()).(2)析 ...
- atitit.Servlet2.5 Servlet 3.0 新特性 jsp2.0 jsp2.1 jsp2.2新特性
atitit.Servlet2.5 Servlet 3.0 新特性 jsp2.0 jsp2.1 jsp2.2新特性 1.1. Servlet和JSP规范版本对应关系:1 1.2. Servlet2 ...
- C# 7.0 新特性3: 模式匹配
本文参考Roslyn项目Issue:#206,及Docs:#patterns. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# ...
- C# 7.0 新特性4: 返回引用
本文参考Roslyn项目中的Issue:#118. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...
- C#发展历程以及C#6.0新特性
一.C#发展历程 下图是自己整理列出了C#每次重要更新的时间及增加的新特性,对于了解C#这些年的发展历程,对C#的认识更加全面,是有帮助的. 二.C#6.0新特性 1.字符串插值 (String In ...
- [转]Servlet 3.0 新特性详解
原文地址:http://blog.csdn.net/xiazdong/article/details/7208316 Servlet 3.0 新特性概览 1.Servlet.Filter.Listen ...
- Servlet3.0新特性
1 Servlet3.0新特性概述 使用要求:MyEclipse10.0或以上版本,发布到Tomcat7.0或以上版本,创建JavaEE6.0应用! Servlete3.0的主要新特性如下三部分: 使 ...
- atitit.j2ee 1.5 1.6 的不同跟 Servlet 3.0新特性总结
atitit.j2ee 1.5 1.6 的不同跟 Servlet 3.0新特性总结 1. jar比较,j2ee 1.6 添加了许多的jar 1 2. ,Servlet 3.0 2 2.1. 可插性 ...
- [C#]6.0新特性浅谈
原文:[C#]6.0新特性浅谈 C#6.0出来也有很长一段时间了,虽然新的特性和语法趋于稳定,但是对于大多数程序猿来说,想在工作中用上C#6.0估计还得等上不短的一段时间.所以现在再来聊一聊新版本带来 ...
随机推荐
- PostgreSQL 传统 hash 分区方法和性能
背景 除了传统的基于trigger和rule的分区,PostgreSQL 10开始已经内置了分区功能(目前仅支持list和range),使用pg_pathman则支持hash分区. 从性能角度,目前最 ...
- NYOJ--7
原题链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=7 分析:x与y分开考虑,分别排序,邮局定在最中间的两个数之间就可以了. 街区最短路径问题 ...
- 三元组ADT (数据结构C语言版) C++实现
很久没用C语言,都忘了C语言中没有引用参数,下面的代码中用到了C语言没有的引用参数. 首先是一些表示状态的全局变量 common.h #define TRUE 1 #define FALSE 0 #d ...
- 对于redis框架的理解(二)
之前梳理过redis main函数主体流程 大体是 initServerConfig() -> loadServerConfig() -> daemonize() -> initSe ...
- Asp.Net Core 依赖注入默认DI,Autofac注入
使用默认DI 修改Startup类方法ConfigureServices如下: public void ConfigureServices(IServiceCollection services) { ...
- Cloudera 安装
参考网址: http://tcxiang.iteye.com/blog/2087597 http://archive.cloudera.com/cdh5/ http://archive.clouder ...
- 【acmm】一道简单的数学题
emm卡常 我本来写成了这个样子: #include<bits/stdc++.h> using namespace std; typedef long long LL; ; struct ...
- 【BZOJ4552】【HEOI2016】排序 [二分答案][线段树]
排序 Time Limit: 60 Sec Memory Limit: 256 MB[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列 ...
- 【CODEVS】2800 送外卖
[算法]最短路(floyd)+状态压缩型动态规划 [题解] 经典的TSP问题(货郎担问题):求最小权哈密顿回路(遍历全图点一次且仅一次).本题稍作改动,先说原TSP问题解法:状压DP. 状态用二进制表 ...
- 【洛谷P2014】选课
题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...