最近再刷了一遍《深入理解C#》,比起上次刷,好像只有泛型和Linq方面的知识加深了理解,果然还是用的少的东西自然理解起来就困难一些。今年C#的版本号已经到了7.0,这本书的第三版是介绍到5.0,趁着这个机会把版本迭代中加入的语言特性做一个简要的总结
C# 1.x
不算后面的小版本号其实是可以统称为C# 1的,但是其实它包含了1.0和1.2两个版本号(没有1.1),分别在2002年和2003年发布。这个版本建立了C#语言的整体框架,面向对象中的封装、继承、多态已经得以很好的体现。
它当时已经提供了下面这些东西:
- 基础数据类型,包含值类型和引用类型
- 非泛型的集合: * ArrayList *
- 事件和委托机制
- 多线程: * Thread *
- APM 异步编程模型: BeginXXX/EndXXX、IAsyncResult......
C# 2.0
C# 2.0版本是2005年末发布的,最亮眼的特性自然就是* 泛型 * ,它也是.Net 2.0的CLR中最重要的特性,其他的一些特性也给开发者提供了极大的便利,还是用列表来总结:
- 泛型,提供了参数化的类型的方法,也带来了最常用的泛型集合,再也不需要考虑装箱和拆箱带来的性能损失了。
- 可空类型,尽管只是语法糖,但是在语义化表达上是进步的
- 匿名方法,对委托来说是极大的语法简化
- 迭代器块,yield关键字
- 分部类 * partial class *
- 静态类 * static class *
除了上面这些,还有些稍小的特性:
- EAP 基于事件的异步模式,支持异步调用中的取消和进度报告(不算特性,但我想体现异步编程的发展历程)
- 属性读写方法的访问修饰符独立
string name;
public string Name
{
get { return name; }
private set { name = value; }
}
- 命名空间别名
- pragma
- 非安全代码中固定大小的缓冲区(对于这条我是一知半解)
C# 3.0
C# 3.0中我们终于迎来了重量级的特性Linq,我在Coding时常常感叹,要是没有Linq,那得多写多少代码。无论是Linq to Object还是的Linq to SQL、Linq to XML,实在是带来了太多的便利,带来了实打实的效率上的提升。
3.0中包含了下面这些新特性:
- Linq
- 自动属性
- 隐式类型的局部变量: * var *
- 对象和集合的初始化器
var list = new List<string> { "AB","CD","EF" };
var tom = new Person { Name="Tom",Age=10 };
- 匿名类型
var tom = new { Name="Tom",Age=10 };
- Lambda表达式和表达式树
- 拓展方法,有了它Linq才是完整的,注意它是到.Net 3.5中才有的
- 分部方法,它是C#类中的"钩子"
C# 4.0
C# 4.0中的特性旨在提高互操作性,因此看起来更像是小修小补(除了动态类型),它包括:
- 命名实参
- 可选参数
- 简化的COM交互性(还记得被Type.Missing支配的恐惧吗)
- 泛型的可变性,协变和逆变获得史诗级buff
- 动态类型 * dynamic * 和与之对应的DLR(这是个巨大的话题,但平时很少接触)
- TAP 基于任务的异步编程模式
C# 5.0
C# 5.0的主旨很明确,就是围绕异步编程进行的。我在写前面版本特性时特地把异步编程的演变放在里面,就是想体现对于异步编程这个主题在时间线上的演变过程,它的三次演变(反别在1.x、2.0和4.0)最终在C#中合并为async和await两个极其简单的语法糖来实现。这个版本提供的特性:
- 基于TPL(任务运行库)的异步编程,async和await关键字封装了大量的代码(从IL来看它们就只是语法糖),极大地简化了异步编程的过程,是用同步的思想实现异步编程的最好体现。
- foreach循环中捕获变量修正,解决了闭包导致的变量捕获问题(js中还得用匿名函数等等方法来解决,C#直接从编译器层面给它改了)
string[] items = { "x","y","z" };
var actions = new List<action>();
foreach(string item in items)
{
actions.add(()=>Console.WriteLine(item)); //输出“xyz”,之前版本是“zzz”
}
- 调用者信息特性(从没用到过的三个Attribute)
C# 6.0
书中没有涉及到C# 6.0的语言特性,下面的内容是根据网上的资料整理的
- 自动属性初始化器
public string Name { get; set; } = "Tom";
Lambda表达式可以用作方法体或属性
字典初始化器,初始化器终于支持字典类型了
var dic = new Dictionary<string, string>()
{
["name"] = "Tom",
["gender"] = "male"
};
使用Using Static引用静态类,调用时可省略类名
catch 块中可以使用 await关键字了
异常过滤器
try
{
...
}
catch (Exception ex) if (ex.InnerException == null)
{
...
}
- 新运算符“?.”,检查对象是否为null,以此决定后续操作
list?.Count; //list不为null则返回属性Count,否则返回null
- 字符串嵌入,即简化的string.Format形式
var tom = new { Name="Tom",Age=10 };
Console.WriteLine($"Age:{tom.Age} Name:{tom.Name}");
nameof表达式,直接获得变量、方法、对象名
无参数的结构体构造函数
C# 7.0
C# 7.0推出还不算太久,和上个版本一样,并没有太亮眼的特性。此部分的内容参考这篇文章[干货来袭]C#7.0新特性(VS2017可用)
out变量可以在使用时直接申明
增强的数据类型元组 * Tuples * (真成大杂烩了)
匹配模式
增强的ref关键字,可用于局部变量和return
局部函数(这.............,我有点看不懂了)
构造函数,析构函数,和属性访问器现在也能用表达式了
throw关键词可用于表达式了
通用的异步返回类型ValueTask<T>,原来的void,Task 或 Task<T>可以被同义替换
允许数字中出现"_"这个分割符号,值不变,只是提高可读性(这.............)