CS 6
read-only auto properties
Small help with immutable types...
// private readonly int _age;
// public int Age { get { return _age; } }
public int Age { get; }
public Person(int age)
{
Age = age;
}
Auto-prop initialization
same as above, its readonly. we can change collection elements but can't override Nicknames.
public IList<string> Nicknames { get; } = new List<string>();
Expression body
private int _age = 10;
public int Age => _age;
public string AgeFormatted => $"{Age:000}";
public int GetAge() => Age + 10;
Using static
using static System.String;
public string Formatted => Format("this is test {0}", 10);
// nested types without base class name
Null-conditional operators
// int? age;
// if person == null, age == null, otherwise age == person.Age
var age = person?.Age;
var ageBis = person?.Age ?? 0;
GetType(age); // int?
GetType(ageBis); // int
static Type GetType<T>(T o)
{
return typeof(T);
}
String interpolation
var name = "Jan";
var surname = "Kowalski";
var fullName = $"{name} {surname}";
// |Left | Right|
var padding = $"|{"Left",-7}|{"Right",7}|";
Filter/guards
For instance we can use to handle status code 404
try
{
}
catch(HttpRequestException hre) when (hre.Message.Contains("404"))
{
// do something for 404
}
catch(HttpRequestException hre) when (hre.Message.Contains("401"))
{
// do something for 401
}
catch(Exception ex)
{
}
nameof
we can refactor name, and its "string" value will change too
public Person(string name)
{
if(name == null)
{
throw new ArgumentNullException(nameof(name));
}
}
few others
static Task DoThings() { return Task.CompletedTask; };
Task.Run(DoThings); // will run, when previously it didn't
Task.Run(() => DoThings());
private Dictionary<int, string> messages = new Dictionary<int, string>
{
{ 404, "Page not Found"},
{ 302, "Page moved, but left a forwarding address."},
{ 500, "The web server can't come out to play today."}
};
// new
private Dictionary<int, string> webErrors = new Dictionary<int, string>
{
[404] = "Page not Found",
[302] = "Page moved, but left a forwarding address.",
[500] = "The web server can't come out to play today."
};
CS 7
out variables
// if(int.TryParse("0001", out var num))
if(int.TryParse("0001", out int num))
{
return num;
}
if(int.TryParse("test", out _))
{
return "Works";
}
else
{
return "It's not a number";
}
touples
finally no more Item1, Item2, Item3, Item4, Item5...
(string FirstName, string LastName, int Age) person = ("Jan", "Kowalski", 33);
var info = $"{person.FirstName} {person.LastName} is {person.Age} old";
// unpacking/destructing
var point = new Point(3, 4);
(int X, int Y) = point;
discards
using _
in declaration, meaning we do not care about result, param etc.
don't use it as parameter name.
pattern matching
if (input is int count)
{
sum += count;
}
public void Do<T>(T a)
{
switch(a)
{
case 0:
break;
case IEnumerable<ushort> myVar:
// do somthing with myVar;
break;
case int n when n > 0:
// do something with n
break;
case null:
default:
break;
}
}
ref returns
public static ref int Find(int[,] matrix, Func<int, bool> predicate) {}
ref var i = ref Find(...);
i = 10;
// we are updating value in metrix passed to Find method on specific index
local functions
public static int DoSomething(string val)
{
if(val == null) {
return generate_code(true);
}
// do some processing
return generate_code(false);
int generate_code(bool isNull)
{
return isNull ? 10 : 0;
}
}
expressions bodies updated
public class Person
{
public string FullName { get; }
public Person(string fullName) => FullName = fullName;
}
private string _fullName;
public string FullName
{
get => _fullName;
set => _fullName = value ?? "Jan Kowalski";
}
other updates
throw
can be used in from expressions bodies or in condiational operatior.
ValueTask
for performance critical async code that might be synchronously or cached. Task is reference type and allocate heap memory.
literals 0b0001_0000
or 0xFF_DD
and 1_000_000
CS 7.1
async main
static async Task<int> Main ()
{
}
default literal expression
// public Task SomeAsync(CancelletionToken ct = default(CancelletionToken)) {}
public Task SomeAsync(CancelletionToken ct = default) {}
int i = default;
int? ni = default;
small imp to touples
var x = 10;
var y = 20;
var point = (x, y);
var namedPoint = (X: x, Y: y);
pattern matching for generit type parameters
public void Method<T>(T param)
{
switch (param)
{
case A a:
Console.WriteLine("A");
break;
case B b:
Console.WriteLine("B");
break;
}
}
CS 7.2
in keyword
// index passed by ref, instead of copy (smaller mem footprint)
// but SomeAction is not allowed to change index
public int SomeAction(in int index, byte[] array)
{
var change = 0;
for(; change < 10; change++)
{
array[index + change] = change;
}
// will not work
// index += change;
return change;
}
readonly/immutable struct
readonly public struct Point3D
{
public Point3D(double x, double y, double z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
public double X { get; }
public double Y { get; }
public double Z { get; }
}
more about ref readonly
https://docs.microsoft.com/en-us/dotnet/csharp/write-safe-efficient-code
one more ref for conditional expressions
ref var r = ref (arr != null ? ref arr[0] : ref otherArr[0]);
// r is a reference to first element of arr or otherArr, chaning r will change value
// in arr or otherArr at index 0
small improvemnt to named arguments
if we have passing argument in proper location, we do not need to provide its name.
better value literals
var bin = 0b_0101_1111;
var hex = 0x_FF_DD_EE;
private protected
protected private
only avaliable to derived classes in the same assembly.
protected internal
only avaliable to derived classes or all others in the same assembly
CS 7.3
Mostly efficient safe code improvements. Like reassigning ref var to differnt location. Also more types support fixed statement, stackalloc allow array initializations, etc.
small improvements to c#
// tupples support == and !=
// backing field will have attached MyFieldAttribute
[field: MyFieldAttribute]
public int MyProp { get; set; }
// out extended to field initialization, property initialization, constructor initialization
var strings = new string[1];
var r = from s in strings
select int.TryParse(s, out var i);
// updates to overload resolution rules
CS 8
more patten matching nad matching expressions
public static string DailyGreeting(DayOfTheWeek day)
{
return day switch
{
DayOfTheWeek.Monday => "It's the luckiest day of the weekly!",
DayOfTheWeek.Tuesday => "",
DayOfTheWeek.Wednesday => "It's hump day",
DayOfTheWeek.Thursday => "It's almost the weekend!",
DayOfTheWeek.Friday => "It's the weekend baby!",
DayOfTheWeek.Saturday => "Party like it's you're on spring break",
DayOfTheWeek.Sunday => "Lazy day...",
_ => throw new ArgumentException("invalid enum value", nameof(day))
};
}
public static decimal ComputeSalesTax(Address location, decimal salePrice) =>
location switch
{
{ State: "WA" } => salePrice * 0.06M,
{ State: "MN" } => salePrice * 0.075M,
{ State: "MI" } => salePrice * 0.05M,
// other cases removed for brevity...
_ => 0M
};
public static string RockPaperScissors(string first, string second)
=> (first, second) switch
{
("rock", "paper") => "rock is covered by paper. Paper wins.",
("rock", "scissors") => "rock breaks scissors. Rock wins.",
("paper", "rock") => "paper covers rock. Paper wins.",
("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
("scissors", "rock") => "scissors is broken by rock. Rock wins.",
("scissors", "paper") => "scissors cuts paper. Scissors wins.",
(_, _) => "tie"
};
using updated
using(var reader = new StringReader(str))
{
var line = reader.ReadLine();
return line;
}
using var reader = new StringReader(str);
var line = reader.ReadLine();
return line;
async using and streams
// IAsyncEnumerable<int> SomeSequence
await foreach(var number in SomeSequence())
{
Console.WriteLine(number);
}
await using (var disposableObject = new DisposableObject())
{
//...
}
await using var disposableObject = new DisposableObject();
nullable reference
we need to set:
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
this will change how reference types works and what warnings we will get. compiler use static anaylysis to detect nulls.
// non-nullable reference type
string name;
// nullable reference type
string? nameBis;
// non-nullable reference type
Person person;
// nullable reference type
Person? personBis;
// we know that personBis is not null, so omit comipiler warning
personBis!.Name;
Person p = null; // warning
Person p = null!; // ok
Person p = default!; // ok
// more about attributes for static analysis
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis
// plus attributes:
// pre-conditions: AllowNull / DisallowNull
// post-condition: NotNull / MaybeNull
// [return: MaybeNull]
// conditional post-condition: NotNullWhen / MayBeNullWhen / NotNullIfNotNull
// [NotNullWhen(returnValue: false)]
indexies
var words = new string[]
{
// index from start index from end
"Siala", // 0 ^9
"baba", // 1 ^8
"mak", // 2 ^7
"nie", // 3 ^6
"wiedziala", // 4 ^5
"jak", // 5 ^4
"a", // 6 ^3
"dziad", // 7 ^2
"wiedzial" // 8 ^1
}; // 9 (or words.Length) ^0
// last word
var last = words[^1];
var previousToLast = words[^2];
// last two words:
var dziadWiedzial = words[^2..^0];
// first four words:
var firstPhrase = words[..4]
Range phrase = 1..4;
var fromRange = words[phrase];
words[^2] = "nie";
words[^1] = "powiedzial";
Null-coalescing assignment
List<int> list = null;
// assign if null
list ??= new List<int>();
int? i = null;
i ??= 10;
i ??= 20;
// i == 10;
other improvements
Adding static local functions (in 7.0 only normal function could be creted in method).
disposable ref structs.
interoplation strings can be delcared $@""
or @$""
.
stackalloc initialization expression can be used in nested expressions.
default interface implementation like => and method mody
CS 9
There is already a post about upcoming changes...
https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/
field notes
- remove discards in swith expression pattern matching
switch
expression on "logical" ifs likeif(a > 10) else if (a <= 9) else
a switch
{
> 10 => aaa,
<= 9 => bbb
null =>
not null =>
}
null
andnot null
patterns- C# 9 removes
public class Program
and allow us to just write statements fromMain
withoutMain
method init
properties
public string Prop { get; init; }
data
keywoard
// for Person class take a loog at the end of this code block, no
// matter how you will specify it, following will work
// no type on new, but type in declaration.
Person p = new { FirstName = "Jan", LastName = "Kowalski" };
// var in declaration, but then type after new
var p = new Person { FirstName = "Jan", LastName = "Kowalski" };
var pp = p with
{
FirstName = "Krzysiek"
};
var ppp = pp with
{
FirstName = "Jan"
};
p equals ppp = true
p reference equals ppp = false
data class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
data class Person
{
string FirstName;
string LastName;
}
data class Person(string FirstName, string LastName);
!
for null check - throws ArgumentNullException
public void Test(string name!) {}
-
override for type
-
BEST EVER function of C# 9 <3 :D
int? i = obj == null ? null : 10;
var b = false;
int? j = b ? 10 : null;
Person p = new { FirstName = "Jan", LastName = "Kowalski" };
Is also valid.