{"id":20485,"date":"2018-12-05T15:51:33","date_gmt":"2018-12-05T23:51:33","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/dotnet\/?p=20485"},"modified":"2020-10-05T19:33:13","modified_gmt":"2020-10-06T02:33:13","slug":"take-c-8-0-for-a-spin","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/take-c-8-0-for-a-spin\/","title":{"rendered":"Take C# 8.0 for a spin"},"content":{"rendered":"<h2>Take C# 8.0 for a spin<\/h2>\n<p>Yesterday we announced the first preview of both Visual Studio 2019 (<a href=\"https:\/\/blogs.msdn.microsoft.com\/visualstudio\/2018\/12\/04\/making-every-developer-more-productive-with-visual-studio-2019\/\">Making every developer more productive with Visual Studio 2019<\/a>) and .NET Core 3.0 (<a href=\"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2018\/12\/04\/announcing-net-core-3-preview-1-and-open-sourcing-windows-desktop-frameworks\/\">Announcing .NET Core 3 Preview 1 and Open Sourcing Windows Desktop Frameworks<\/a>). One of the exciting aspects of that is that you get to play with some of the features coming in C# 8.0! Here I am going to take you on a little guided tour through three new C# features you can try out in the preview. Not all C# 8.0 features are available yet. If you want an overview of all the major features, go read the recent post <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/building-c-8-0\/\">Building C# 8.0<\/a>, or check the short (13 mins) video &#8220;What&#8217;s new in C# 8.0&#8221; on <a href=\"https:\/\/channel9.msdn.com\/events\/Connect\/Microsoft-Connect--2018\/D140\">Channel 9<\/a> or <a href=\"https:\/\/www.youtube.com\/watch?v=VdC0aoa7ung&amp;list=PLReL099Y5nRcDayMMgYIA6q7lMbqXz_Gv&amp;index=16\">YouTube<\/a>.<\/p>\n<h2>Getting ready<\/h2>\n<p>First of all, download and install <a href=\"https:\/\/aka.ms\/netcore3download\">Preview 1 of .NET Core 3.0<\/a> and <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\">Preview 1 of Visual Studio 2019<\/a>. In Visual Studio, make sure you select the workload &#8220;.NET Core cross-platform development&#8221; (if you forgot, you can just add it later by opening the Visual Studio Installer and clicking &#8220;Modify&#8221; on the Visual Studio 2019 Preview channel). Launch Visual Studio 2019 Preview, Create a new project, and select &#8220;Console App (.NET Core)&#8221; as the project type. Once the project is up and running, change its target framework to .NET Core 3.0 (right click the project in Solution Explorer, select Properties and use the drop down menu on the Application tab). Then select C# 8.0 as the language version (on the Build tab of the project page click &#8220;Advanced&#8230;&#8221; and select &#8220;C# 8.0 (beta)&#8221;). Now you have all the language features and the supporting framework types ready at your fingertips!<\/p>\n<h2>Nullable reference types<\/h2>\n<p>The nullable reference types feature intends to warn you about null-unsafe behavior in the code. Since we didn&#8217;t do that before, it would be a breaking change to just start now! To avoid that, you need to opt in to the feature. Before we do turn it on, though, let&#8217;s write some really bad code:<\/p>\n<pre class=\"lang:default decode:true\">using static System.Console;\n\nclass Program\n{\n    static void Main(string[] args)\n    {\n        string s = null;\n        WriteLine($\"The first letter of {s} is {s[0]}\");\n    }\n}\n<\/pre>\n<p>If you run it you get, of course, a null reference exception. You&#8217;ve fallen into the black hole! How were you supposed to know not to dereference <code>s<\/code> in that particular place? Well duh, because null was assigned to it on the previous line. But in real life, it&#8217;s not on the previous line, but in somebody else&#8217;s assembly running on the other side of the planet three years after you wrote your line of code. <em>How could you have known not to write that?<\/em><\/p>\n<p>That&#8217;s the question that nullable reference types set out to answer! So let&#8217;s turn them on! For a new project you should just turn them on right away. In fact I think they should probably be on by default in new projects, but we didn&#8217;t do that in the preview. The way to turn them on is to add the following line to your .csproj file, e.g. right after the LanguageVersion that was just inserted when you switched to C# 8.0 above:<\/p>\n<pre class=\"lang:default decode:true\">&lt;Nullable&gt;enable&lt;\/Nullable&gt;\n<\/pre>\n<p>Save the .csproj file and return to your program: What happened? You got two warnings! Each represents one &#8220;half&#8221; of the feature. Let&#8217;s look at them in turn. The first one is on the <code>null<\/code> in this line:<\/p>\n<pre class=\"lang:default decode:true\">string s = null;\n<\/pre>\n<p>It complains that you are assigning null to a &#8220;non-nullable type&#8221;: Whaaat?!? When the feature is turned on <em>nulls are no longer welcome in ordinary reference types<\/em> such as <code>string<\/code>! Because, you know what, <em>null is not a string<\/em>! We&#8217;ve been pretending for the last fifty years of object-oriented programming, but actually null is in fact not an object: That&#8217;s why everything explodes whenever you try to treat it like one! So no more of that: null is verboten, unless you ask for it.<\/p>\n<p>How <em>do<\/em> you ask for it? By using a nullable reference type, such as <code>string?<\/code>. The trailing question mark signals that null is allowed:<\/p>\n<pre class=\"lang:default decode:true\">string? s = null;\n<\/pre>\n<p>The warning goes away: we have explicitly expressed the intent for this variable to hold null, so now it&#8217;s fine.<\/p>\n<p>Until the next line of code! On the line<\/p>\n<pre class=\"lang:default decode:true\">WriteLine($\"The first letter of {s} is {s[0]}\");\n<\/pre>\n<p>It complains about the <code>s<\/code> in <code>s[0]<\/code> that you may be dereferencing a null reference. And sure enough: you are! Well done, compiler! How do you fix it, though? Well that&#8217;s pretty much up to you &#8211; whichever way you would always have fixed it! Let&#8217;s try for starters to only execute the line when <code>s<\/code> is not null:<\/p>\n<pre class=\"lang:default decode:true\">if (s != null) WriteLine($\"The first letter of {s} is {s[0]}\");\n<\/pre>\n<p>The warning goes away! Why? Because the compiler can see that you only go to the offending code when <code>s<\/code> is <em>not<\/em> null. It actually does a full flow analysis, tracking every variable across every line of code to keep tabs on where it might be null and where it probably won&#8217;t be. It watches your tests and assignments, and does the bookkeeping. Let&#8217;s try another version:<\/p>\n<pre class=\"lang:default decode:true\">WriteLine($\"The first letter of {s} is {s?[0] ?? '?'}\");\n<\/pre>\n<p>This uses the null conditional indexing operator <code>s?[0]<\/code> which avoids the dereference and produces a null if <code>s<\/code> is null. Now we have a nullable <code>char?<\/code>, but the null-coalescing operator <code>?? '?'<\/code> replaces a null value with the <code>char<\/code> <code>'?'<\/code>. So all null dereferences are avoided. The compiler is happy, and no warnings are given.<\/p>\n<p>As you can see, the feature keeps you honest while you code: it forces you to express your intent whenever you want null in the system, by using a nullable reference type. And once null is there, it forces you to deal with it responsibly, making you check whenever there&#8217;s a risk that a null value may be dereferenced to trigger a null reference exception.<\/p>\n<p>Are you completely null-safe now? No. There are a couple of ways in which a null may slip through and cause a null reference exception:<\/p>\n<ul>\n<li>If you call code that didn&#8217;t have the nullable reference types feature on (maybe it was compiled before the feature even existed), then we cannot know what the intent of that code was: it doesn&#8217;t distinguish between nullable and nonnullable &#8211; we say that it is &#8220;null-oblivious&#8221;. So we give it a pass; we simply don&#8217;t warn on such calls. <\/li>\n<li>The analysis itself has certain holes. Most of them are a trade-off between safety and convenience; if we complained, it would be really hard to fix. For instance, when you write <code>new string[10]<\/code>, we create an array full of nulls, typed as non-null <code>string<\/code>s. We don&#8217;t warn on that, because how would the compiler keep track of you initializing all the array elements? <\/li>\n<\/ul>\n<p>But on the whole, if you use the feature extensively (i.e. turn it on everywhere) it should take care of the vast majority of null dereferences.<\/p>\n<p>It is definitely our intention that you should start using the feature on existing code! Once you turn it on, you may get a lot of warnings. Some of these actually represent a problem: Yay, you found a bug! Some of them are maybe a bit annoying; your code is clearly null safe, you just didn&#8217;t have the tools to express your intent when you wrote it: you didn&#8217;t have nullable reference types! For instance, the line we started out with:<\/p>\n<pre class=\"lang:default decode:true\">string s = null;\n<\/pre>\n<p>That&#8217;s going to be super common in existing code! And as you saw, we did get a warning on the next line, too, where we tried to dereference it. So the assignment warning here is strictly speaking superfluous from a safety standpoint: It keeps you honest in <em>new<\/em> code, but fixing all occurences in <em>existing<\/em> code would not make it any safer. For that kind of situation we are working on a mode where certain warnings are turned off, when it doesn&#8217;t impact the null safety, so that it is less daunting to upgrade existing code.<\/p>\n<p>Another feature to help upgrade is that you can turn the feature on or off &#8220;locally&#8221; in your code, using compiler directives <code>#nullable enable<\/code> and <code>#nullable disable<\/code>. That way you can go through your project and deal with annotations and warnings gradually, piece by piece.<\/p>\n<p>To learn more about nullable reference types check out the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/csharp\/nullable-references\">Overview of Nullable types<\/a> and the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/csharp\/tutorials\/nullable-reference-types\">Introduction to nullable tutorial<\/a> on <a href=\"https:\/\/docs.microsoft.com\">docs.microsoft.com<\/a>. For a deeper design rationale, last year 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>. If you want to immerse yourself in the day-to-day of the design work, look at the <a href=\"https:\/\/github.com\/dotnet\/csharplang\/blob\/master\/meetings\/2018\/README.md\">Language Design Notes<\/a> on GitHub, or follow along as I try to put together a <a href=\"https:\/\/github.com\/dotnet\/csharplang\">Nullable Reference Types Specification<\/a>.<\/p>\n<h2>Ranges and indices<\/h2>\n<p>C# is getting more expressiveness around working with indexed data structures. Ever wanted simple syntax for slicing out a part of an array, string or span? Now you can! Go ahead and change your program to the following:<\/p>\n<pre class=\"lang:c# decode:true\">using System.Collections.Generic;\nusing static System.Console;\n\nclass Program\n{\n    static void Main(string[] args)\n    {\n        foreach (var name in GetNames())\n        {\n            WriteLine(name);\n        }\n    }\n\n    static IEnumerable&lt;string&gt; GetNames()\n    {\n        string[] names =\n        {\n            \"Archimedes\", \"Pythagoras\", \"Euclid\", \"Socrates\", \"Plato\"\n        };\n        foreach (var name in names)\n        {\n            yield return name;\n        }\n    }\n}\n<\/pre>\n<p>Let&#8217;s go to that bit of code that iterates over the array of names. Modify the <code>foreach<\/code> as follows:<\/p>\n<pre class=\"lang:default decode:true\">foreach (var name in names[1..4])\n<\/pre>\n<p>It looks like we&#8217;re iterating over names 1 to 4. And indeed when you run it that&#8217;s what happens! The endpoint is <em>exclusive<\/em>, i.e. element 4 is not included. <code>1..4<\/code> is actually a range expression, and it doesn&#8217;t have to occur like here, as part of an indexing operation. It has a type of its own, called <code>Range<\/code>. If we wanted, we could pull it out into its own variable, and it would work the same:<\/p>\n<pre class=\"lang:default decode:true\">Range range = 1..4; \n        foreach (var name in names[range])\n<\/pre>\n<p>The endpoints of a range expression don&#8217;t have to be ints. In fact they&#8217;re of a type, <code>Index<\/code>, that non-negative ints convert to. But you can also create an <code>Index<\/code> with a new <code>^<\/code> operator, meaning &#8220;from end&#8221;. So <code>^1<\/code> is one from the end:<\/p>\n<pre class=\"lang:default decode:true\">foreach (var name in names[1..^1])\n<\/pre>\n<p>This lobs off an element at each end of the array, producing an array with the middle three elements. Range expressions can be open at either or both ends. <code>..^1<\/code> means the same as <code>0..^1<\/code>. <code>1..<\/code> means the same as <code>1..^0<\/code>. And <code>..<\/code> means the same as <code>0..^0<\/code>: beginning to end. Try them all out and see! Try mixing and matching &#8220;from beginning&#8221; and &#8220;from end&#8221; <code>Index<\/code>es at either end of a <code>Range<\/code> and see what happens.<\/p>\n<p>Ranges aren&#8217;t just meant for use in indexers. For instance, we plan to have overloads of <code>string.SubString<\/code>, <code>Span&lt;T&gt;.Slice<\/code> and the <code>AsSpan<\/code> extension methods that take a <code>Range<\/code>. Those aren&#8217;t in this Preview of .NET Core 3.0 though.<\/p>\n<h2>Asynchronous streams<\/h2>\n<p><code>IEnumerable&lt;T&gt;<\/code> plays a special role in C#. &#8220;IEnumerables&#8221; represent all kinds of different sequences of data, and the language has special constructs for consuming and producing them. As we see in our current program, they are consumed through the <code>foreach<\/code> statement, which deals with the drudgery of obtaining an enumerator, advancing it repeatedly, extracting the elements along the way, and finally disposing the enumerator. And they can be produced with <em>iterators<\/em>: Methods that <code>yield return<\/code> their elements as they are being asked for by a consumer.<\/p>\n<p>Both are synchronous, though: the results better be ready when they are asked for, or the thread blocks! <code>async<\/code> and <code>await<\/code> were added to C# to deal with results that are <em>not<\/em> necessarily ready when you ask for them. They can be asynchronously <code>await<\/code>ed, and the thread can go do other stuff until they become available. But that works only for single values, not sequences that are gradually and asynchronously produced over time, such as for instance measurements from an IoT sensor or streaming data from a service. Asynchronous streams bring async and enumerables together in C#! Let&#8217;s see how, by gradually &#8220;async&#8217;ifying&#8221; our current program.<\/p>\n<p>First, let&#8217;s add another <code>using<\/code> directive at the top of the file:<\/p>\n<pre class=\"lang:default decode:true\">using System.Threading.Tasks;\n<\/pre>\n<p>Now let&#8217;s simulate that <code>GetNames<\/code> does some asynchronous work by adding an asynchronous delay before the name is <code>yield return<\/code>ed:<\/p>\n<pre class=\"lang:default decode:true\">await Task.Delay(1000);\n            yield return name;\n<\/pre>\n<p>Of course we get an error that you can only <code>await<\/code> in an <code>async<\/code> method. So let&#8217;s make it async:<\/p>\n<pre class=\"lang:default decode:true\">static async IEnumerable&lt;string&gt; GetNames()\n<\/pre>\n<p>Now we&#8217;re told that we&#8217;re not returning the right type for an async method, which is fair. But there&#8217;s a new candidate on the list of types it <em>can<\/em> return besides the usual <code>Task<\/code> stuff: <code>IAsyncEnumerable&lt;T&gt;<\/code>. <em>This is our async version of <code>IEnumerable&lt;T&gt;<\/code><\/em>! Let&#8217;s return that:<\/p>\n<pre class=\"lang:default decode:true\">static async IAsyncEnumerable&lt;string&gt; GetNames()\n<\/pre>\n<p>Just like that we&#8217;ve produced an asynchronous stream of strings! In accordance with naming guidelines, let&#8217;s rename <code>GetNames<\/code> to <code>GetNamesAsync<\/code>.<\/p>\n<pre class=\"lang:default decode:true\">static async IAsyncEnumerable&lt;string&gt; GetNamesAsync()\n<\/pre>\n<p>Now we get an error on this line in the <code>Main<\/code> method:<\/p>\n<pre class=\"lang:default decode:true\">foreach (var name in GetNamesAsync())\n<\/pre>\n<p>Which doesn&#8217;t know how to foreach over an <code>IAsyncEnumerable&lt;T&gt;<\/code>. That&#8217;s because foreach&#8217;ing over asynchronous streams requires explicit use of the <code>await<\/code> keyword:<\/p>\n<pre class=\"lang:default decode:true\">await foreach (var name in GetNamesAsync())\n<\/pre>\n<p>It&#8217;s the version of foreach that takes an async stream and awaits every element! Of course it can only do that in an async method, so we have to make our <code>Main<\/code> method async. Fortunately C# 7.2 added support for that:<\/p>\n<pre class=\"lang:default decode:true\">static async Task Main(string[] args)\n<\/pre>\n<p>Now all the squiggles are gone, and the program is correct. But if you try compiling and running it, you get an embarassing number of errors. That&#8217;s because we messed up a bit, and didn&#8217;t get the previews of .NET Core 3.0 and Visual Studio 2019 perfectly aligned. Specifically, there&#8217;s an implementation type that async iterators leverage that&#8217;s different from what the compiler expects. You can fix this by adding a separate source file to your project, containing <a href=\"https:\/\/github.com\/dotnet\/coreclr\/issues\/21379#issuecomment-444473061\">this bridging code<\/a>. Compile again, and everything should work just fine.<\/p>\n<h2>Next steps<\/h2>\n<p>Please let us know what you think! If you try these features and have ideas for how to improve them, please use the feedback button in the Visual Studio 2019 Preview. The whole purpose of a preview is to have a last chance to course correct, based on how the features play out in the hands of real life users, so <em>please let us know!<\/em><\/p>\n<p>Happy hacking,<\/p>\n<p>Mads Torgersen, Design Lead for C#<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Take C# 8.0 for a spin Yesterday we announced the first preview of both Visual Studio 2019 (Making every developer more productive with Visual Studio 2019) and .NET Core 3.0 (Announcing .NET Core 3 Preview 1 and Open Sourcing Windows Desktop Frameworks). One of the exciting aspects of that is that you get to play [&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":[4,9,46,147],"class_list":["post-20485","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-csharp","tag-net","tag-net-core","tag-c","tag-visual-studio"],"acf":[],"blog_post_summary":"<p>Take C# 8.0 for a spin Yesterday we announced the first preview of both Visual Studio 2019 (Making every developer more productive with Visual Studio 2019) and .NET Core 3.0 (Announcing .NET Core 3 Preview 1 and Open Sourcing Windows Desktop Frameworks). One of the exciting aspects of that is that you get to play [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/20485","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=20485"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/20485\/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=20485"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=20485"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=20485"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}