搜索
首页后端开发C#.Net教程C# 7.0 语言新特性

C# 7.0 语言新特性

Apr 29, 2017 pm 05:26 PM

  下面是关于在C#7.0语言中计划功能的说明。其中大部分功能在Visual Studio “15” Preview 4中能运行。现在是最好的试用时期,请记录下你们的想法。

  C#7.0语言增加了许多的新功能,促使专注于数据消费,简化代码和性能。

  或许最大的特征是元组(tuples) ,使得它易于有多个结果,并从而简化代码是以对数据的形状为条件的模式匹配。但也有许多其他的一些功能希望将它们结合起来,让代码运行更高效,更明确,从而获得更多的创造性。如果有哪些运行不是你想要的或者有想改进的功能,在Visual Studio的窗口顶部使用“send feedback”功能将结果反馈给我们。在我所描述的许多功能在Preview 4还没有办法充分运行,根据用户的反馈结果,我们将在发布最终版是增加些新的功能。而必须要指出的是,现有计划中的一些功能在最终版也可能会有所改变或取消。

  如果你对这个功能设置感兴趣并想学习它,在Roslyn GitHub site上可以找到许多的设计说明和相关讨论。

  输出(out)变量

  目前在C#中,使用out参数并不像我们想象中那么流畅。在使用out参数调用方法时,你首先必须声明变量传递给它。虽然你通常不会初始化这些变量(他们将通过该方法后所有被覆盖),也不能使用VAR来声明他们,但是需要指定完整的类型:

public void PrintCoordinates(Point p)
{    int x, y; // have to "predeclare"
    p.GetCoordinates(out x, out y);
    WriteLine($"({x}, {y})");
}

  在C#7.0,我们增加了Out变量,作为out参数传递的点来声明一个变量权:

public void PrintCoordinates(Point p)
{
    p.GetCoordinates(out int x, out int y);
    WriteLine($"({x}, {y})");
}

  需要注意的是,变量是在封闭块范围内,所以后续可以使用它们。大多数类型的语句不建立自己的适用范围,因此out变量通常在声明中被引入到封闭范围。

:在Preview 4中,适用范围规则更为严格:out变量的作用域为它们在声明的说法。因此,上面的例子不会在后续的版本中使用。

  由于out变量直接声明作为参数传递给out参数,编译器通常可以告知类型(除非有冲突的过载)。所以这是很好用VAR,而不是一个类型来声明它们:

p.GetCoordinates(out var x, out var y);

  out参数的一个常见的用途是Try...模式,其中out参数一个boolean return表示成功,out参数进行得到的结果:

public void PrintStars(string s)
{    if (int.TryParse(s, out var i)) { WriteLine(new string('*', i)); }    else { WriteLine("Cloudy - no stars tonight!"); }
}

:Preview 4处理的比较好的地方在于只是用if语句定义它。

  计划允许“wildcards”作为out参数以及在*的形式,忽视不重要的out参数:

p.GetCoordinates(out int x, out *); // I only care about x

注:wildcards能否把它变成C#7.0还是个未知数。

  模式匹配

  C# 7.0 引入了模式的概念,抽象地说,这是一种语法成分可以用来测试一个值是否有一个一定的“形”以及在它起作用时从值里面获取到的额外信息。

  下面是 C# 7.0 中关于模式的例子:

  • c 的常量模式(c 是C#中的一个常量表达式),用于测试输入的参数是否和 c 相等


  • T x 的类型模式(T 是一个类型,x 是一个标识符),用于测试输入的参数是否有类型 T,如果有,提取输入参数的值到一个 T 类型的新 x 变量中。


  • var x 变量模式(x 是一个标识符),通常会匹配并简单地将输入参数的值放进一个新变量 x 中

  这是个开始,模式是一种新的 C# 语言元素,而且我们将来可以把它们更多地增加到 C# 中。

  在 C# 7.0 中,我们正在使用模式以增强两种已存在的语言结构:

  • is 表达式现在在右边可以有一个模式,而不只是一个类型


  • case 子句在 switch 语句中现在可以通过模式匹配,而不仅仅是常量值

  在将来的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));
}

  正如你所看到的,模式变量(变量通过模式引入)与先前描述的 out 变量有些类似,他们可以在表达式中被声明,而且可以在它们最近的周围范围内被使用。也像 out 变量那样,模式变量是易变的,

: 就像 out 变量一样,严格的范围规则适用于 Preview 4.

  模式和 Try 方法通常会一起出现:

if (o is int i || (o is string s && int.TryParse(s, out i)) { /* use i */ }

  带模式的 Switch 语句

  我们正在泛化 switch 语句,因此:

  • 你可以在任何类型上使用 switch(不仅仅是原始类型)


  • 可以在 case 子句中使用模式


  • Case 子句可以拥有额外的条件

  这里是一个简单的例子:

switch(shape)
{
    case Circle c:
        WriteLine($"circle with radius {c.Radius}");
        break;
    case Rectangle s when (s.Length == s.Height):
        WriteLine($"{s.Length} x {s.Height} square");
        break;
    case Rectangle r:
        WriteLine($"{r.Length} x {r.Height} rectangle");
        break;
    default:
        WriteLine("<unknown shape>");
        break;
    case null:
        throw new ArgumentNullException(nameof(shape));
}

  有几件关于这个新扩展的 switch 语句的事需要注意:

  • case 子句的顺序现在很重要:就像 catch 子句,case 子句不再是必然不相交的,第一个子句匹配的将被选择。因此这里重要的是上面代码中 square case 比 rectangle case 来得要早。也是和 catch 子句一样,编译器会通过标记明显不能到达的情况来帮助你。在这之前,你永远无法知道评价的顺序,所以这不是一个重大改变的特性。


  • 默认子句总是最后被评价:即使上面代码中 null 子句是最后才来,它会在默认子句被选择前被检查。这是为了与现有 switch 语义相兼容。然而,好的做法通常会让你把默认子句放到最后。


  • null 子句在最后不可到达:这是因为类型模式遵循当前的 is 表达式的例子并且不会匹配空值。这保证了空值不会偶然被任何的类型模式捎来第一抢购。你必须更明确如何处理它们(或为默认子句留下他们)。

  通过 case ...: 标签引入的模式变量仅存在于相对应的 switch 部分的范围内。

  元组

  这是常见的希望从一个方法返回多个值的做法。目前可用的选项不是最佳的:

  • Out 参数。使用笨拙(即便有上面描述到的提升),它们不使用异步的方法运行。


  • System.Tupleca6ded975897b2776a8a23c57d5020a5  返回类型。使用累赘并且需要一个元组对象的分配。


  • 为每个方法定制传输类型:大量的代码为了类型开销的目的仅是临时收集一些值


  • 匿名类型通过返回一个 dynamic 返回类型。高性能开销并且没有静态类型检查。

  为了在这方面做得更好,C# 添加了tuple types  tuple literals:

(string, string, string) LookupName(long id) // tuple return type
{
    ... // retrieve first, middle and last from data storage
    return (first, middle, last); // tuple literal
}

  这个方法目前有效地返回三个字符串,将其作为元素在元组类型里包裹起来。

  方法的调用者将会接受到一个元组,并且可以逐一访问元素。

var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");

  Item1 等等,是元组元素的默认名字,并能够经常被使用。但它们不是太好描述的,因此你可以选择性地添加更好的一个。

(string first, string middle, string last) LookupName(long id) // tuple elements have names

  现在元组的接受者拥有更多的可描述的名字用于运行:

var names = LookupName(id);
WriteLine($"found {names.first} {names.last}.");

  你也可以在 tuple literals 中直接指定名字:

return (first: first, middle: middle, last: last); // named tuple elements in a literal

  通常来说,你可以互相分配元组类型无关的名字,只要独立的元素是可以被分配的,元组类型会自如 转换成其他元组类型。特别是对于 tuple literals ,存在一些限制,这会警告或提示在常见的错误的情况下提示,例如偶然交换元素的名字。

注意:这些限制还没在 Preview 4 中实现

  元组是值类型,而且他们的元素只是公开、易变的域。他们的值相等,代表这两个元组是相等的(都有相同的哈斯码)如果它们的元素都结对匹配(都有相同的哈斯码)。

  这使得元组对于在多种返回值下的很多情况十分有用。举例来说,如果你需要一个有多种键的词典,使用元组作为你的键,然后一切东西就会如常工作。如果你需要在每个位置有一个有多种值的列表,使用元组,查找列表等等,程序会正常运行。

注意:元组依赖一系列底层类型,它们在 Preview 4 中不被引入。为了将来的工作,你可以通过 NuGget 轻易获取它们: 在 Solution Explorer 中右键点击项目,并选择“Manage NuGet Packages…” 选择“Browse”选项卡,检查“Include prerelease” 并且选择“nuget.org”作为“Package source” 搜索“System.ValueTuple”并安装它

  解构

  另一种消除元组(tuple)的方法是解构元组。通过一个解构声明语法,把一个元组(或者其他的值)拆分为几部分,并且重新定义为新的变量。

(string first, string middle, string last) = LookupName(id1); // deconstructing decla
rationWriteLine($"found {first} {last}.");

  在解构中可采用var关键字:

(var first, var middle, var last) = LookupName(id1); // var inside

  或者把var关键字提取出来,在括号外:

var (first, middle, last) = LookupName(id1); // var outside

  你也可以通过解构赋值来解构一个现有变量:

(first, middle, last) = LookupName(id2); // deconstructing assignment

  不仅仅元组可以被解构,任何类型都可以被解构,只要有一个对应的(实体或者扩展)解构方法:

public void Deconstruct(out T1 x1, ..., out Tn xn) { ... }

  输出参数由解构之后的结果值构成。

  (为什么采用数据参数代替返回一个元组?这样,你可以重载多个不同的数值)

class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) { X = x; Y = y; }
    public void Deconstruct(out int x, out int y) { x = X; y = Y; }
}

(var myX, var myY) = GetPoint(); // calls Deconstruct(out myX, out myY);

  这将成为一种常见模式,包含析构函数和“对称”解析:

  针对输出变量,我们计划在解构中允许使用“通配符”:

(var myX, *) = GetPoint(); // I only care about myX
   注:仍然还没有确定是否将通配符引入C# 7.0中。

  局部函数

  有时,一个辅助函数只在一个使用它的单一方法内部有意义。现在你可以在其他功能体内部声明这些函数作为一个局部函数:

public int Fibonacci(int x)
{
    if (x < 0) throw new ArgumentException("Less negativity please!", nameof(x));
    return Fib(x).current;

    (int current, int previous) Fib(int i)
    {
        if (i == 0) return (1, 0);
        var (p, pp) = Fib(i - 1);
        return (p + pp, p);
    }
}

  参数和闭合区间局部变量可用在局部函数内,类似lambda表达式。

  举一个例子,方法实现迭代器通常需要严格检查调用时非迭代器封装方法。(迭代器本身没有运行,只到调用MoveNext 才会运行)。局部函数在这种情况下是完美的:

public IEnumerable<T> Filter<T>(IEnumerable<T> source, Func<T, bool> filter)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (filter == null) throw new ArgumentNullException(nameof(filter));

    return Iterator();

    IEnumerable<T> Iterator()
    {
        foreach (var element in source) 
        {
            if (filter(element)) { yield return element; }
        }
    }
}

  如果迭代器是一个私有方法的下一个过滤器,它将有可能被其他成员不小心使用(没有参数检查)。此外,作为过滤器,它将需要采取所有的相同的参数,而不是指定域内的参数。

   注:在Preview 4版本中,本地函数必须在它们被调用之前声明。这个限制将被放松,能调用读取直接赋值的局部变量。

  Literal 改进

  C# 7.0 允许使用“_”作为数字分隔符在数字literals中:

var d = 123_456;
var x = 0xAB_CD_EF;

  你可以把它放在你想要的位置,提升可读性。这样对数值没有任何影响。

  此外,C# 7.0也介绍了二进制literals,这样你可以直接指定二进制模式而不必知道十六进制符号。

var b = 0b1010_1011_1100_1101_1110_1111;

  Ref 返回和本地

  就像你可以通过reference(用ref修饰符)在C#中传递东西,您现在可以通过reference return 他们,并通过 reference将它们存储在局部变量中。

public ref int Find(int number, int[] numbers)
{
    for (int i = 0; i < numbers.Length; i++)
    {
        if (numbers[i] == number) 
        {
            return ref numbers[i]; // return the storage location, not the value
        }
    }
    throw new IndexOutOfRangeException($"{nameof(number)} not found");
}

int[] array = { 1, 15, -39, 0, 7, 14, -12 };
ref int place = ref Find(7, array); // aliases 7&#39;s place in the array
place = 9; // replaces 7 with 9 in the array
WriteLine(array[4]); // prints 9

  这对绕过占位符成为大数据结构是非常有用的。举例来说,一个游戏可能会在一个大的预分配数组结构中保存其数据(为避免垃圾收集暂停)。Methods 可以直接返回一个 reference 到这样一个结构,且通过调用者可以读取和修改它。

  这里有一些限制,以确保这是安全的:

  • 你可以只返回 refs 那些是 “安全返回(safe to return)”的:那些被传递给你的,和那些点到对象的字段。


  • Ref locals被初始化为某一存储位置,并且不能突变到指向另一个。

  广义异步返回类型

  截至目前为止,在C#调用异步方法必须要返回void,Task或Task8742468051c85b06f0a0af9e3e506b5c。C#7.0允许以这样的方式来定义其它类型,从而使它们可以从异步方法返回。

  例如,我们计划有一个ValueTask8742468051c85b06f0a0af9e3e506b5c结构类型。它是建立在预防Task8742468051c85b06f0a0af9e3e506b5c 对象的分配时,异步操作的结果是已在可等候的时间的情况下。对于很多异步场景,比如以涉及缓冲为例, 这可以大大减少分配的数量,并使性能有显著提升。

  这里有许多其他的方法可以让您想象自定义“task-like”类型是有用的。它不会是简单的正确创建,所以我们不要指望大多数人推出自己的,但他们很可能将会开始在框架和API展现出来,然后调用方可以返回并await他们今天做任务(Tasks)的方式。

    注:广义异步返回类型尚未应用在预览4。    

  更多 Expression-bodied 方法

  Expression-bodied 方法、属性等都是C# 6.0的重大突破,但并不允许他们在各种各样的member中使用,C#7.0添加了访问器、构造函数和终结器等,使更多member可以使用Expression-bodied 方法:

class Person
{
    private static ConcurrentDictionary<int, string> names = new ConcurrentDictionary<int, string>();
    private int id = GetId();

    public Person(string name) => names.TryAdd(id, name); // constructors
    ~Person() => names.TryRemove(id, out *);              // destructors
    public string Name
    {
        get => names[id];                                 // getters
        set => names[id] = value;                         // setters
    }
}
注:这些额外的Expression-bodied 方法还没有工作在预览4。

  这是一个由社区贡献的特征,而非微软C#团队。并且,开源!

  在表达式的中间抛出一个异常是很容易的,只需要为你自己调用一个方法,但在C#7.0中我们允许在一些地方直接抛出表达式:

class Person
{
    public string Name { get; }
    public Person(string name) => Name = name ?? throw new ArgumentNullException(name);
    public string GetFirstName()
    {
        var parts = Name.Split(" ");
        return (parts.Length > 0) ? parts[0] : throw new InvalidOperationException("No name!");
    }
    public string GetLastName() => throw new NotImplementedException();
}
  注:抛出表达式还未在预览4工作。

  本文地址:http://www.oschina.net/translate/whats-new-in-csharp-7-0

  原文地址:https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/

以上是C# 7.0 语言新特性的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
C#.NET:探索核心概念和编程基础知识C#.NET:探索核心概念和编程基础知识Apr 10, 2025 am 09:32 AM

C#是一种现代、面向对象的编程语言,由微软开发并作为.NET框架的一部分。1.C#支持面向对象编程(OOP),包括封装、继承和多态。2.C#中的异步编程通过async和await关键字实现,提高应用的响应性。3.使用LINQ可以简洁地处理数据集合。4.常见错误包括空引用异常和索引超出范围异常,调试技巧包括使用调试器和异常处理。5.性能优化包括使用StringBuilder和避免不必要的装箱和拆箱。

测试C#.NET应用程序:单元,集成和端到端测试测试C#.NET应用程序:单元,集成和端到端测试Apr 09, 2025 am 12:04 AM

C#.NET应用的测试策略包括单元测试、集成测试和端到端测试。1.单元测试确保代码的最小单元独立工作,使用MSTest、NUnit或xUnit框架。2.集成测试验证多个单元组合的功能,常用模拟数据和外部服务。3.端到端测试模拟用户完整操作流程,通常使用Selenium进行自动化测试。

高级C#.NET教程:ACE您的下一次高级开发人员面试高级C#.NET教程:ACE您的下一次高级开发人员面试Apr 08, 2025 am 12:06 AM

C#高级开发者面试需要掌握异步编程、LINQ、.NET框架内部工作原理等核心知识。1.异步编程通过async和await简化操作,提升应用响应性。2.LINQ以SQL风格操作数据,需注意性能。3..NET框架的CLR管理内存,垃圾回收需谨慎使用。

C#.NET面试问题和答案:提高您的专业知识C#.NET面试问题和答案:提高您的专业知识Apr 07, 2025 am 12:01 AM

C#.NET面试问题和答案包括基础知识、核心概念和高级用法。1)基础知识:C#是微软开发的面向对象语言,主要用于.NET框架。2)核心概念:委托和事件允许动态绑定方法,LINQ提供强大查询功能。3)高级用法:异步编程提高响应性,表达式树用于动态代码构建。

使用C#.NET建筑微服务:建筑师实用指南使用C#.NET建筑微服务:建筑师实用指南Apr 06, 2025 am 12:08 AM

C#.NET是构建微服务的热门选择,因为其生态系统强大且支持丰富。1)使用ASP.NETCore创建RESTfulAPI,处理订单创建和查询。2)利用gRPC实现微服务间的高效通信,定义和实现订单服务。3)通过Docker容器化微服务,简化部署和管理。

C#.NET安全性最佳实践:防止常见漏洞C#.NET安全性最佳实践:防止常见漏洞Apr 05, 2025 am 12:01 AM

C#和.NET的安全最佳实践包括输入验证、输出编码、异常处理、以及身份验证和授权。1)使用正则表达式或内置方法验证输入,防止恶意数据进入系统。2)输出编码防止XSS攻击,使用HttpUtility.HtmlEncode方法。3)异常处理避免信息泄露,记录错误但不返回详细信息给用户。4)使用ASP.NETIdentity和Claims-based授权保护应用免受未授权访问。

c语言中:是什么意思c语言中:是什么意思Apr 03, 2025 pm 07:24 PM

C 语言中冒号 (':') 的含义:条件语句:分隔条件表达式和语句块循环语句:分隔初始化、条件和增量表达式宏定义:分隔宏名和宏值单行注释:表示从冒号到行尾的内容为注释数组维数:指定数组的维数

c语言中a  是什么意思c语言中a 是什么意思Apr 03, 2025 pm 07:21 PM

C 语言的 a 是后增运算符,其运作机制包括:先获取变量 a 的值。将 a 的值增加 1。返回自增后的 a 的值。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器