{"id":20105,"date":"2018-11-12T16:00:02","date_gmt":"2018-11-13T00:00:02","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/dotnet\/?p=20105"},"modified":"2020-10-05T19:33:15","modified_gmt":"2020-10-06T02:33:15","slug":"building-c-8-0","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/building-c-8-0\/","title":{"rendered":"Building C# 8.0"},"content":{"rendered":"<h2>Building C# 8.0<\/h2>\n<p>The next major version of C# is C# 8.0. It&#8217;s been in the works for quite some time, even as we built and shipped the minor releases C# 7.1, 7.2 and 7.3, and I&#8217;m quite excited about the new capabilities it will bring.<\/p>\n<p>The current plan is that C# 8.0 will ship at the same time as .NET Core 3.0. However, the features will start to come alive with the previews of Visual Studio 2019 that we are working on. As those come out and you can start trying them out in earnest, we will provide a whole lot more detail about the individual features. The aim of this post is to give you an overview of what to expect, and a heads-up on where to expect it.<\/p>\n<h2>New features in C# 8.0<\/h2>\n<p>Here&#8217;s an overview of the most significant features slated for C# 8.0. There are a number of smaller improvements in the works as well, which will trickle out over the coming months.<\/p>\n<h2>Nullable reference types<\/h2>\n<p>The purpose of this feature is to help prevent the ubiquitous null reference exceptions that have riddled object-oriented programming for half a century now.<\/p>\n<p>It stops you from putting <code>null<\/code> into ordinary reference types such as <code>string<\/code> &#8211; it makes those types non-nullable! It does so gently, with warnings, not errors. But on existing code there will be new warnings, so you have to opt in to using the feature (which you can do at the project, file or even source line level).<\/p>\n<pre class=\"lang:c# decode:true\">\r\nstring s = null; \/\/ Warning: Assignment of null to non-nullable reference type\r\n<\/pre>\n<p>What if you <em>do<\/em> want null? Then you can use a <em>nullable reference type<\/em>, such as <code>string?<\/code>:<\/p>\n<pre class=\"lang:c# decode:true\">\r\nstring? s = null; \/\/ Ok\r\n<\/pre>\n<p>When you try to use a nullable reference, you need to check it for null first. The compiler analyzes the flow of your code to see if a null value could make it to where you use it:<\/p>\n<pre class=\"lang:c# decode:true\">\r\nvoid M(string? s)\r\n{\r\n    Console.WriteLine(s.Length); \/\/ Warning: Possible null reference exception\r\n    if (s != null)\r\n    {\r\n        Console.WriteLine(s.Length); \/\/ Ok: You won't get here if s is null\r\n    }\r\n}\r\n<\/pre>\n<p>The upshot is that C# lets you express your &#8220;nullable intent&#8221;, and warns you when you don&#8217;t abide by it.<\/p>\n<h2>Async streams<\/h2>\n<p>The async\/await feature of C# 5.0 lets you consume (and produce) asynchronous results in straightforward code, without callbacks:<\/p>\n<pre class=\"lang:c# decode:true\">\r\nasync Task&lt;int&gt; GetBigResultAsync()\r\n{\r\n    var result = await GetResultAsync();\r\n    if (result &gt; 20) return result; \r\n    else return -1;\r\n}\r\n<\/pre>\n<p>It is not so helpful if you want to consume (or produce) continuous streams of results, such as you might get from an IoT device or a cloud service. Async streams are there for that.<\/p>\n<p>We introduce <code>IAsyncEnumerable&lt;T&gt;<\/code>, which is exactly what you&#8217;d expect; an asynchronous version of <code>IEnumerable&lt;T&gt;<\/code>. The language lets you <code>await foreach<\/code> over these to consume their elements, and <code>yield return<\/code> to them to produce elements.<\/p>\n<pre class=\"lang:c# decode:true\">\r\nasync IAsyncEnumerable&lt;int&gt; GetBigResultsAsync()\r\n{\r\n    await foreach (var result in GetResultsAsync())\r\n    {\r\n        if (result &gt; 20) yield return result; \r\n    }\r\n}\r\n<\/pre>\n<h2>Ranges and indices<\/h2>\n<p>We&#8217;re adding a type <code>Index<\/code>, which can be used for indexing. You can create one from an <code>int<\/code> that counts from the beginning, or with a prefix <code>^<\/code> operator that counts from the end:<\/p>\n<pre class=\"lang:c# decode:true\">\r\nIndex i1 = 3;  \/\/ number 3 from beginning\r\nIndex i2 = ^4; \/\/ number 4 from end\r\nint[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };\r\nConsole.WriteLine($\"{a[i1]}, {a[i2]}\"); \/\/ \"3, 6\"\r\n<\/pre>\n<p>We&#8217;re also introducing a <code>Range<\/code> type, which consists of two <code>Index<\/code>es, one for the start and one for the end, and can be written with a <code>x..y<\/code> <em>range expression<\/em>. You can then index with a <code>Range<\/code> in order to produce a slice:<\/p>\n<pre class=\"lang:c# decode:true\">\r\nvar slice = a[i1..i2]; \/\/ { 3, 4, 5 }\r\n<\/pre>\n<h2>Default implementations of interface members<\/h2>\n<p>Today, once you publish an interface it&#8217;s game over: you can&#8217;t add members to it without breaking all the existing implementers of it.<\/p>\n<p>In C# 8.0 we let you provide a body for an interface member. Thus, if somebody doesn&#8217;t implement that member (perhaps because it wasn&#8217;t there yet when they wrote the code), they will just get the default implementation instead.<\/p>\n<pre class=\"lang:c# decode:true\">\r\ninterface ILogger\r\n{\r\n    void Log(LogLevel level, string message);\r\n    void Log(Exception ex) =&gt; Log(LogLevel.Error, ex.ToString()); \/\/ New overload\r\n}\r\n\r\nclass ConsoleLogger : ILogger\r\n{\r\n    public void Log(LogLevel level, string message) { ... }\r\n    \/\/ Log(Exception) gets default implementation\r\n}\r\n<\/pre>\n<p>The <code>ConsoleLogger<\/code> class doesn&#8217;t have to implement the <code>Log(Exception)<\/code> overload of <code>ILogger<\/code>, because it is declared with a default implementation. Now you can add new members to existing public interfaces as long as you provide a default implementation for existing implementors to use.<\/p>\n<h2>Recursive patterns<\/h2>\n<p>We&#8217;re allowing patterns to contain other patterns:<\/p>\n<pre class=\"lang:c# decode:true\">\r\nIEnumerable&lt;string&gt; GetEnrollees()\r\n{\r\n    foreach (var p in People)\r\n    {\r\n        if (p is Student { Graduated: false, Name: string name }) yield return name;\r\n    }\r\n}\r\n<\/pre>\n<p>The pattern <code>Student { Graduated: false, Name: string name }<\/code> checks that the <code>Person<\/code> is a <code>Student<\/code>, then applies the constant pattern <code>false<\/code> to their <code>Graduated<\/code> property to see if they&#8217;re still enrolled, and the pattern <code>string name<\/code> to their <code>Name<\/code> property to get their name (if non-null). Thus, if <code>p<\/code> is a <code>Student<\/code>, has not graduated and has a non-null name, we <code>yield return<\/code> that name.<\/p>\n<h2>Switch expressions<\/h2>\n<p>Switch statements with patterns are quite powerful in C# 7.0, but can be cumbersome to write. Switch expressions are a &#8220;lightweight&#8221; version, where all the cases are expressions:<\/p>\n<pre class=\"lang:c# decode:true\">\r\nvar area = figure switch \r\n{\r\n    Line _      =&gt; 0,\r\n    Rectangle r =&gt; r.Width * r.Height,\r\n    Circle c    =&gt; Math.PI * c.Radius * c.Radius,\r\n    _           =&gt; throw new UnknownFigureException(figure)\r\n};\r\n<\/pre>\n<h2>Target-typed new-expressions<\/h2>\n<p>In many cases, when you&#8217;re creating a new object, the type is already given from context. In those situations we&#8217;ll let you omit the type:<\/p>\n<pre class=\"lang:c# decode:true\">\r\nPoint[] ps = { new (1, 4), new (3,-2), new (9, 5) }; \/\/ all Points\r\n<\/pre>\n<p><span>The implementation of this feature was <a href=\"https:\/\/github.com\/dotnet\/roslyn\/pull\/25196\">contributed<\/a> by a member of the community, <a href=\"https:\/\/github.com\/alrz\">Alireza Habibi<\/a>. Thank you!<\/span><\/p>\n<h2>Platform dependencies<\/h2>\n<p>Many of the C# 8.0 language features have platform dependencies. Async streams, indexers and ranges all rely on new framework types that will be part of .NET Standard 2.1. As Immo describes in his post <a href=\"https:\/\/blogs.msdn.microsoft.com\/dotnet\/\">Announcing .NET Standard 2.1<\/a>, .NET Core 3.0 as well as Xamarin, Unity and Mono will all implement .NET Standard 2.1, but .NET Framework 4.8 will not. This means that the types required to use these features won&#8217;t be available on .NET Framework 4.8. Likewise, default interface member implementations rely on new runtime enhancements, and we will not make those in the .NET Runtime 4.8 either. <\/p>\n<p>For this reason, using C# 8.0 is only supported on platforms that implement .NET Standard 2.1. The need to keep the runtime stable has prevented us from implementing new language features in it for more than a decade. With the side-by-side and open-source nature of the modern runtimes, we feel that we can responsibly evolve them again, and do language design with that in mind. Scott explained in his <a href=\"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2018\/10\/04\/update-on-net-core-3-0-and-net-framework-4-8\/\">Update on .NET Core 3.0 and .NET Framework 4.8<\/a> that .NET Framework is going to see less innovation in the future, instead focusing on stability and reliability. Given that, we think it is better for it to miss out on some language features than for nobody to get them.<\/p>\n<h2>How can I learn more?<\/h2>\n<p>The C# language design process is open source, and takes place in the <a href=\"https:\/\/github.com\/dotnet\/csharplang\">github.com\/dotnet\/csharplang)<\/a> repo. It can be a bit overwhelming and chaotic if you don&#8217;t follow along regularly. The heartbeat of language design is the language design meetings, which are captured in the <a href=\"https:\/\/github.com\/dotnet\/csharplang\/blob\/master\/meetings\/2018\/README.md\">C# Language Design Notes<\/a>.<\/p>\n<p>About a year ago I wrote a post <a href=\"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2017\/11\/15\/nullable-reference-types-in-csharp\/\">Introducing Nullable Reference Types in C#<\/a>. It should still be an informative read.<\/p>\n<p>You can also watch videos such as <a href=\"https:\/\/channel9.msdn.com\/events\/Build\/2018\/BRK2155\">The future of C#<\/a> from Microsoft Build 2018, or <a href=\"https:\/\/channel9.msdn.com\/events\/dotnetConf\/2018\/S103\">What&#8217;s Coming to C#?<\/a> from .NET Conf 2018, which showcase several of the features.<\/p>\n<p>Kathleen has a great post laying out the plans for <a href=\"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2018\/11\/12\/visual-basic-in-net-core-3-0\/\">Visual Basic in .NET Core 3.0<\/a>.<\/p>\n<p>As we start releasing the features as part of Visual Studio 2019 previews, we will also publish much more detail about the individual features.<\/p>\n<p>Personally I can&#8217;t wait to get them into the hands of all of you!<\/p>\n<p>Happy hacking,<\/p>\n<p>Mads Torgersen, Design Lead for C#<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Building C# 8.0 The next major version of C# is C# 8.0. It&#8217;s been in the works for quite some time, even as we built and shipped the minor releases C# 7.1, 7.2 and 7.3, and I&#8217;m quite excited about the new capabilities it will bring. The current plan is that C# 8.0 will ship [&hellip;]<\/p>\n","protected":false},"author":1379,"featured_media":21739,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[756],"tags":[11,43,61],"class_list":["post-20105","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-csharp","tag-net-framework","tag-bcl","tag-docs"],"acf":[],"blog_post_summary":"<p>Building C# 8.0 The next major version of C# is C# 8.0. It&#8217;s been in the works for quite some time, even as we built and shipped the minor releases C# 7.1, 7.2 and 7.3, and I&#8217;m quite excited about the new capabilities it will bring. The current plan is that C# 8.0 will ship [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/20105","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/1379"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=20105"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/20105\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/21739"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=20105"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=20105"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=20105"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}