Last active
May 21, 2022 01:04
-
-
Save divega/aa23a0f22f6dca3654677d37590298b9 to your computer and use it in GitHub Desktop.
Playing with recent and upcoming features from C# 8.0 through 11.0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// What's new in C# | |
// Good places to start: | |
// - https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-version-history#c-version-72 | |
// - https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-11 | |
#region implicit and global usings (C# 10) | |
global using Microsoft.EntityFrameworkCore; | |
global using System.Collections; | |
using System; | |
#endregion | |
#region top-level statements (C# 10) | |
Console.WriteLine("Waiting to start..."); | |
// await Task.Delay(TimeSpan.FromMinutes(5)); | |
Console.WriteLine("Hello team!"); | |
#endregion | |
#region raw strings (C# 11) | |
// This is a raw string, new in C# 11 preview. No more pain pasting your JSON into code! | |
Console.WriteLine(""" | |
{ | |
"glossary": { | |
"title": "example glossary", | |
"GlossDiv": { | |
"title": "S", | |
"GlossList": { | |
"GlossEntry": { | |
"ID": "SGML", | |
"SortAs": "SGML", | |
"GlossTerm": "Standard Generalized Markup Language", | |
"Acronym": "SGML", | |
"Abbrev": "ISO 8879:1986", | |
"GlossDef": { | |
"para": "A meta-markup language, used to create markup languages such as DocBook.", | |
"GlossSeeAlso": ["GML", "XML"] | |
}, | |
"GlossSee": "markup" | |
} | |
} | |
} | |
} | |
} | |
"""); | |
// What about interpolated strings? | |
Console.WriteLine($$$""" | |
{ | |
"glossary": { | |
"title": "example glossary", | |
"GlossDiv": { | |
"title": "{{{"S"}}}", | |
"GlossList": { | |
"GlossEntry": { | |
"ID": "SGML", | |
"SortAs": "SGML", | |
"GlossTerm": "Standard Generalized Markup Language", | |
"Acronym": "SGML", | |
"Abbrev": "ISO 8879:1986", | |
"GlossDef": { | |
"para": "A meta-markup language, used to create markup languages such as DocBook.", | |
"GlossSeeAlso": ["GML", "XML"] | |
}, | |
"GlossSee": "markup" | |
} | |
} | |
} | |
} | |
} | |
"""); | |
#endregion | |
#region interpolated string improvements | |
// See https://sharplab.io/#v2:EYLgtghglgdgNAExAagD4AEBMBGAsAKAPQGYACLc7AdgIG8DTHKA2cgFlIFloYAKASlIMmtIfiYTKABlLBSAXlIAiAB5KA3MMnTSAZwAuAJwWkAJEoi6EAM1rAAvhq2T02AJy8Dh/pvHax/qQAxgD2MAY6QSaqTn7aoeH6kWFeJuaWNrRBjr6Brh4JXj4EzvYE9kA=== | |
#endregion | |
#region switch expressions (C# 8), caller argument expression (C# 10), list matching (C# 11) | |
var list = new[] { 1, 2, 3, 4 }; | |
Describe(list); | |
Describe(new[] { 1, 2, 3 }); | |
Describe(Array.Empty<int>()); | |
Describe("I am not a list"); | |
static void Describe<T>(T parameter, [System.Runtime.CompilerServices.CallerArgumentExpression("parameter")] string? name = default) => | |
Console.WriteLine($""" | |
The expression "{name}" represents { // multi-line expressions and comments in the interpolated string "holes" (C# 11) | |
parameter switch | |
{ | |
IList and [var a, var b, _] => $"a list of 3 elements, {a}, {b}, and some other element we don't care about", | |
IList and [var a, ..] => $"a non-empty list that starts with {a}", | |
IList and { Count: 0 } => "an empty list", | |
_ => "something that isn't a list" | |
}}. | |
"""); | |
#endregion | |
#region async streams (using EF Core) (C# 8), nullable reference types (C# 8), init-only settters (C# 9) | |
{ // Let's persist some data. | |
using var context = new DatabaseContext(); // using declaration (gets disposed automatically at the end of the of scope) | |
await context.Database.EnsureDeletedAsync(); | |
await context.Database.EnsureCreatedAsync(); | |
context.Add( | |
new Person | |
{ | |
Id = 1, | |
PartitionKey = "1", | |
FirstName = "John", | |
LastName = "Doe" | |
}); | |
context.Add( | |
new Person | |
{ | |
Id = 2, | |
PartitionKey = "2", | |
FirstName = "Jane", | |
LastName = "Doe" | |
}); | |
await context.SaveChangesAsync(); | |
} | |
{ // Let's query some data. | |
using var context = new DatabaseContext(); // using declaration (gets disposed automatically at then end of scope) | |
// To see how foreach works, see https://sharplab.io/#v2:EYLgtghglgdgNAExAagD4AEBMBGAsAKHQAYACdbAOgBlYBHAbgIPQGYzMzsB2EgbyfwkhnAGxkALCQCy0GAAoAlHwLDVJAG4QATiQBmEANYBTAIoBXI1oCeJALwkYRgO4kA2gF0+AIghe4JL2A/AIBjLwBfCgBBAGdzSysIYAAbI0VGQTUhXQB7LSMIEIALOU0dIxJYPUNTC2sFFSzlTKbhAGEcmBic1IoAdS0oABc0owUM1vDGoSn8cKA== | |
await foreach (var person in context.People.Where(p => p.LastName == "Doe").AsAsyncEnumerable().WithCancellation(default)) | |
{ | |
Console.WriteLine($"Here is a person: {person.FirstName} {person.LastName}"); | |
} | |
Console.WriteLine(); | |
} | |
public class Person | |
{ | |
public int Id { get; set; } | |
// ! is the new "null-forgiving operator". | |
// Assigning default! signals the compiler we don't need to be warned that the non-nullable property isn't initialized. | |
public string PartitionKey { get; set; } = default!; | |
public string? FirstName { get; set; } | |
public string LastName { get; set; } = default!; | |
} | |
public class DatabaseContext : DbContext | |
{ | |
public DbSet<Person> People { get; init; } = default!; // Initialization-only settters | |
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | |
{ | |
optionsBuilder.UseCosmos( | |
"AccountEndpoint = https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", | |
"MyDatabase"); | |
} | |
} | |
#endregion | |
#region generic attributes (C# 11) | |
public class DefaultDatabaseValue<T> : Attribute | |
{ | |
public DefaultDatabaseValue(T value) | |
{ | |
Value = value; | |
} | |
public T Value { get; } | |
} | |
public class PersonTest | |
{ | |
[DefaultDatabaseValue<int>(0)] | |
public int Id { get; set; } | |
[DefaultDatabaseValue<string>("J. Doe")] | |
public string? Name { get; set; } | |
} | |
#endregion | |
#region readonly struct members (C#8) | |
public struct Point | |
{ | |
public double X { get; set; } | |
public double Y { get; set; } | |
public readonly Measure Z { get; } | |
public readonly double Distance => Math.Sqrt(X * X + Y * Y); | |
public readonly override string ToString() => $"({X}, {Y}) is {Distance} from the origin"; | |
} | |
public struct Measure | |
{ | |
public readonly double Member { get; } | |
} | |
#endregion | |
#region records (C# 9) | |
// See https://sharplab.io/#v2:EYLgtghglgdgNAExAagD4AEBMBGAsAKAPQGYACLc7AdlIG8CDSnKA2cgFlIFloYAKAJR1GzUQAUApgCcAzgHsYAJQkBjOVISkADtPkxSAXlIwJAdz4AiAFIA6C3AsARORIsCA3CNFMv3gG4QUqQArloIEAAuEgiSsgqG2rrxplARABZ0pABiULIRAHIQYBIJ1hAmFqQAvp743sy+oujYAJx8jfWkACQWACppJaHhUZo6cTAA5DKkAGa5MhHGRSVQ0/R1naJDkdGxejY5eYXFVW61HT4b9c1tPRYWF960Y3pVpKvCV5vefC8KAIQGbYjPYKAD8pAsMDkiwsIEhbkeoiqEgAjsEIAAbOjA3ZJGBVJHMe5nXy+Qn4ClEMhSVTqTSgpR0jR8ZoABmy8wKyzglA5ABkIAtjhIPETvp1qaRaWoNKQAKJgLSYuQATwkJVZ2A5h2FPL5pEFeuKvPZCqVKvVUgE8N8jOUsoQfF13JNhqFrtFtSAA= | |
#endregion | |
#region UTF8 strings | |
// See https://sharplab.io/#v2:EYLgtghglgdgNAExAagD4AEBMBGAsAKAPQGYACLc7AdlIG8CDSnKA2cgFlIFloYAKAJR1GzUcACeAFwCmAbQC6pAK6SAZgA4AypIBOsAOakAvKQBEACWkAbKwHtSAVQAqAMXWltemPoDOAQlMldQBuEVEmdGwATj4VDU8DAVD8UQBfMNICVKA=== | |
#endregion | |
#region default interface methods (C# 8) | |
// See https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-8#default-interface-methods | |
#endregion | |
#region indices and ranges (C#8) | |
// See https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-8#indices-and-ranges | |
#endregion | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>net6.0</TargetFramework> | |
<ImplicitUsings>enable</ImplicitUsings> | |
<Nullable>enable</Nullable> | |
<LangVersion>11</LangVersion> | |
<EnablePreviewFeatures>True</EnablePreviewFeatures> | |
</PropertyGroup> | |
<ItemGroup> | |
<None Include="..\.editorconfig" Link=".editorconfig" /> | |
</ItemGroup> | |
<ItemGroup> | |
<PackageReference Include="Microsoft.EntityFrameworkCore.Cosmos" Version="7.0.0-preview*" /> | |
</ItemGroup> | |
</Project> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment