以下将是 C# 7.0 中所有计划的语言特性的描述。随着 Visual Studio “15” Preview 4 版本的发布,这些特性中的大部分将活跃起来。现在是时候来展示这些特性,你也告诉借此告诉我们你的想法!
C#7.0 增加了许多新功能,并专注于数据消费,简化代码和性能的改善。或许最大的特性就是元祖和模式匹配,元祖可以很容易地拥有多个返回结果,而模型匹配可以根据数据的“形”的不同来简化代码。我们希望,将它们结合起来,从而使你的代码更加简洁高效,也可以使你更加快乐并富有成效。
请点击 Visual Studio 窗口顶部的反馈按钮,告诉我们哪些是你不期待的特性或者你关于提升这些特性的思考。还有许多功能没有在 Preview 4 版本中实现。接下来我会描述一些我们发布的最终版本里将会起作用的特性,和一些一旦不起作用机即会删除掉的特性。我也是支持对这些计划作出改变,尤其是作为我们从你那儿得到反馈的结果。当最终版本发布时,这些特性中的一些将会改变或者删除。
如果你好奇这些特性的设计过程,你可以在 Roslyn GitHub site 上找到很多设计笔记和讨论。
希望 C#7.0 能带给你快乐!
输出变量
在当前的 C# 中,使用输出参数并不像我们想的那样方便。在你调用一个无输出参数的方法之前,首先必须声明一个变量并传递给它。如果你没有初始化这些变量,你就无法使用 var 来声明它们,除非先指定完整的类型:
public void PrintCoordinates(Point p)
{
int x, y; // have to "predeclare"
p.GetCoordinates(out x, out y);
WriteLine($"({x}, {y})");
}
在 C#7.0 中,我们正在增加输出变量和声明一个作为能够被传递的输出实参的变量的能力:
public void PrintCoordinates(Point p)
{
p.GetCoordinates(out int x, out int y);
WriteLine($"({x}, {y})");
}
注意,变量是在封闭块的范围内,所以后续也可以使用它们。大多数类型的声明不建立自己的范围,因此在他们中声明的变量通常会被引入到封闭范围。
Note:在 Preview 4 中,适用范围规则更为严格:输出变量的作用域是声明它们的语句,因此直到下个版本发布时,上面的示例才会起作用。
由于输出变量直接被声明为实参传递给输出形参,编译器通常会告诉他们应该是的类型(除非有冲突过载),所以使用 var 来代替声明它们的方式是比较好的:
p.GetCoordinates(out var x, out var y);
输出参数的一种常见用法是Try模式,其中一个布尔返回值表示成功,输出参数就会携带所获的结果:
public void PrintStars(string s)
{
if (int.TryParse(s, out var i)) { WriteLine(new string('*', i)); }
else { WriteLine("Cloudy - no stars tonight!"); }
}
注意:这里i只用在 if 语句来定义它,所以 Preview 4 可以将这个处理的很好。
我们计划允许以 a* 为形式的“通配符”作为输出参数,这会让你忽略了你不关心参数:
p.GetCoordinates(out int x, out *); // I only care about x
Note:在 C#7.0 中是否会包含通配符还不确定。
模式匹配
C# 7.0 引入了模式概念。抽象地讲,模式是句法元素,能用来测试一个数据是否具有某种“形”,并在被应用时,从值中提取有效信息。
C#7.0 中的模式示例:
•C 形式的常量模式(C是C#中的常量表达式),可以测试输入是否等于C
•T X 形式的类型模式(T是一种类型、X是一个标识符),可以测试输入是否是T类型,如果是,会将输入值提取成T类型的新变量X
•Var x 形式的 Var 模式(x是一个标识符),它总是匹配的,并简单地将输入值以它原本的类型存入一个新变量X中。
这仅仅是个开始 - 模式是一种新型的 C# 中的语言元素。未来,我们希望增加更多的模式到 C# 中。
在 C#7.0,我们正在加强两个现有的具有模式的语言结构:
•is 表达式现在具有一种右手侧的模式,而不仅仅是一种类型
•switch 语句中的 case 语句现在可以使用匹配模式,不只是常数值
在 C#的未来版本中,我们可能会增加更多的被用到的模式。
具有模式的 IS 表达式
下面是使用 is 表达式的示例,其中利用了常量模式和类型模式:
public void PrintStars(object o)
{
if (o is null) return; // constant pattern "null"
if (!(o is int i)) return; // type pattern "int i"
WriteLine(new string('*', i));
}
正如你们看到,模式变量(模式引入的变量)和早前描述的输出变量比较类似,它们可以在表达式中间声明,并在最近的范围内使用。就像输出变量一样,模式变量是可变的。
注:就像输出变量一样,严格范围规则适用于Preview 4。
模式和 Try方法可以很好地协同:
if (o is int i || (o is string s && int.TryParse(s, out i)) { /* use i */ }
具有模式的 Switch 语句