Goals: Less boilerplate code for simple use cases,
make C# simpler to approach
System.Console.WriteLine("Hello World!");using System;
using System.Threading.Tasks;
await Task.Delay(100);
Console.WriteLine("Hello World!");
using System;
using System.Threading.Tasks;
if (args.Length == 0)
{
Console.Error.WriteLine("Arguments missing");
return;
}
Console.WriteLine($"Received {args[0]}");
Use top-level async/await
Access command-line arguments
Tip: Take a look at FeatherHttp
Goal: Enable use of local functions in more scenarios
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureServices(services =>
{
services
.AddAuthentication("MyScheme")
.AddScheme<DummyAuthenticationOptions, DummyAuthenticationHandler>("MyScheme", options => { });
services.AddAuthorization();
})
.Configure(app =>
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
static async Task SayHello(HttpContext context) => await context.Response.WriteAsync("Public view");
endpoints.MapGet("/", SayHello);
[Authorize(AuthenticationSchemes = "MyScheme", Roles = "Admin")]
static async Task AdminsOnly(HttpContext context) => await context.Response.WriteAsync("Admin view");
endpoints.MapGet("/secret", AdminsOnly);
});
});
})
.Build().Run();Goal: Let the compiler infer the type in more cases
// `default` operator
Console.WriteLine(default(int)); // output: 0
Console.WriteLine(default(object) is null); // output: True
// Since C# 7: `default` literal
// Initialization
int x = default;
// Default arguments
static T GetElementAtIndex<T>(int index = default) { ... }
// Argument value
static TOutput Map<TInput, TOutput>(TInput objectToTransform, Func<TInput, TOutput> transformFunction, bool log) { ... }
Map("Hi", s => s.ToUpper(), default);
// Return statement
static int Div(int x, int y) => y == 0 ? default : x / y;
using System;
struct S { }
class CtorWithParameters
{
public CtorWithParameters(int x) { /* ... */ }
}
class C
{
public static void Main()
{
int x1 = new();
var x2 = (int)new();
(int x, int y) point = new();
C myClass = new();
var myClass2 = (C)new();
myClass = null;
myClass ??= new();
CtorWithParameters myClass4 = new(42);
S myStruct = new();
}
}using System;
using System.Collections.Generic;
class Person
{
public string FirstName { get; }
public string LastName { get; }
public Person(string firstName, string lastName) => (FirstName, LastName) = (firstName, lastName);
}
class C
{
public static void Main()
{
List<Person> people = new()
{
new("Foo", "Bar"),
new("John", "Doe")
};
var list = new[] { new C(), new() }; // list will be C[]
var list2 = new[] { new Person("Foo", "Bar"), new("John", "Doe") };
}
}class CreationOptions { /* ... */}
class C
{
static T Factory<T>() where T : new() => new();
static T Factory<T>(CreationOptions options) where T : new()
{
// Check options
return new();
}
public static void Main()
{
var program = Factory<C>(new());
}
}using System.Collections.Generic;
class Person
{
public string FirstName { get; }
public string LastName { get; }
public Person(string firstName, string lastName)
=> (FirstName, LastName) = (firstName, lastName);
}
class Manager : Person
{
public bool IsSenior { get; }
public Manager(string firstName, string lastName, bool isSenior)
: base(firstName, lastName)
=> IsSenior = isSenior;
}
class Employee : Person
{
public bool IsIntern { get; }
public Employee(string firstName, string lastName, bool isIntern)
: base(firstName, lastName)
=> IsIntern = isIntern;
}
class Program
{
static void Main()
{
Dictionary<Manager, List<Employee>> orgChart = new()
{
{
new("Foo", "Bar", true),
new()
{
new("John", "Doe", true),
new("Jane", "Smith", false)
}
}
};
}
}using System;
using System.Collections.Generic;
class Person
{
public string FirstName { get; }
public string LastName { get; }
public Person(string firstName, string lastName)
=> (FirstName, LastName) = (firstName, lastName);
}
class Program
{
static IEnumerable<Person> GetPeople()
{
for (var i = 0; i < 10; i++)
{
yield return new($"Foo{i++}", "Bar");
}
}
static void Main()
{
foreach (var person in GetPeople())
{
Console.WriteLine(person);
}
}
}enum HeroType
{
NuclearAccident, FailedScienceExperiment,
Alien, Mutant,
Other
};
enum HeroTypeCategory
{
Accident, SuperPowersFromBirth, Other
}
class Hero
{
public Hero(HeroTypeCategory category) { }
}
class Program
{
static void Main()
{
var ht = HeroType.FailedScienceExperiment;
Hero h = ht switch
{
HeroType.Alien or HeroType.Mutant => new(HeroTypeCategory.SuperPowersFromBirth),
HeroType.FailedScienceExperiment or HeroType.NuclearAccident => new(HeroTypeCategory.Accident),
_ => new(HeroTypeCategory.Other)
};
}
}Goal: No longer invent dummy parameter names in lambda expressions
MathOperation<int> add = (a, b) => a + b;
// Previously:
MathOperation<int> dummyOld = (_, __) => 42;
// Now:
MathOperation<int> dummyNew = (_, _) => 42;
delegate T MathOperation<T>(T a, T b);Goal: Make pattern matching even more useful
using System;
var age = 84;
if (age is >= 65)
{
Console.WriteLine("Is senior");
}
var ageCategory = age switch
{
< 13 => "child",
< 18 => "teenager",
< 65 => "adult",
_ => "senior"
};
Console.WriteLine(ageCategory);
enum HeroType
{
NuclearAccident, FailedScienceExperiment,
Alien, Mutant,
Other
};
enum HeroTypeCategory
{
Accident, SuperPowersFromBirth, Other
}
class Hero
{
public Hero(HeroTypeCategory category) { }
}
class Program
{
static void Main()
{
var ht = HeroType.FailedScienceExperiment;
Hero h;
if (ht is HeroType.Alien or HeroType.Mutant)
{
h = new(HeroTypeCategory.SuperPowersFromBirth);
}
}
}using System;
class Program
{
static void Main()
{
var letter = 'x';
bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');
Console.WriteLine(IsLetter(letter));
var number = 42;
bool IsInRange(int n) => n is > 40 and < 50;
Console.WriteLine(IsInRange(number));
object someObject = number;
if (someObject is int and not < 42) Console.WriteLine("High Number");
}
}Goal: Make data-only classes and structs simpler
using System;
class Program
{
public static void Main()
{
var p = new Point(42, 84);
Console.WriteLine($"{p.X}/{p.Y}");
}
}
record Point(int X, int Y);
using System;
class Program
{
public static void Main()
{
var p1 = new Point(42, 84);
var p2 = new Point(42, 84);
Console.WriteLine(p1.Equals(p2));
}
}
record Point(int X, int Y);using System;
var c = new C(0, 1);
Console.WriteLine(c); // prints: 0 1
c = c with { X = 5 };
Console.WriteLine(c); // prints: 5 1
c = c with { Y = 2 };
Console.WriteLine(c); // prints: 5 2
record C(int X, int Y)
{
public override string ToString() => X + " " + Y;
}
What didn't we mention here (because too early, only for a small niche, etc.)?
Goal: Generate Code in VS and during compilation