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"})
这段代码完成了两件事:
- 它创建了一个本地变量s,将其赋值为((Professor) person) .Subject。
- 它执行了一次相等性检查 ((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)”的场景,例如在代码中注入日志记录、安全检查、参数校验以及其他各种繁琐的样板式代码。