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;
}
same as above, its readonly. we can change collection elements but can't override Nicknames.
public IList<string> Nicknames { get; } = new List<string>();
private int _age = 10;
public int Age => _age;
public string AgeFormatted => $"{Age:000}";
public int GetAge() => Age + 10;
using static System.String;
public string Formatted => Format("this is test {0}", 10);
// nested types without base class name
// 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);
}
var name = "Jan";
var surname = "Kowalski";
var fullName = $"{name} {surname}";
// |Left | Right|
var padding = $"|{"Left",-7}|{"Right",7}|";
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)
{
}
we can refactor name, and its "string" value will change too
public Person(string name)
{
if(name == null)
{
throw new ArgumentNullException(nameof(name));
}
}
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."
};
// 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";
}
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;
using _
in declaration, meaning we do not care about result, param etc.
don't use it as parameter name.
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;
}
}
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
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;
}
}
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";
}
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
static async Task<int> Main ()
{
}
// public Task SomeAsync(CancelletionToken ct = default(CancelletionToken)) {}
public Task SomeAsync(CancelletionToken ct = default) {}
int i = default;
int? ni = default;
var x = 10;
var y = 20;
var point = (x, y);
var namedPoint = (X: x, Y: y);
public void Method<T>(T param)
{
switch (param)
{
case A a:
Console.WriteLine("A");
break;
case B b:
Console.WriteLine("B");
break;
}
}
// 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 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; }
}
https://docs.microsoft.com/en-us/dotnet/csharp/write-safe-efficient-code
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
if we have passing argument in proper location, we do not need to provide its name.
var bin = 0b_0101_1111;
var hex = 0x_FF_DD_EE;
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
Mostly efficient safe code improvements. Like reassigning ref var to differnt location. Also more types support fixed statement, stackalloc allow array initializations, etc.
// 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
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(var reader = new StringReader(str))
{
var line = reader.ReadLine();
return line;
}
using var reader = new StringReader(str);
var line = reader.ReadLine();
return line;
// IAsyncEnumerable<int> SomeSequence
await foreach(var number in SomeSequence())
{
Console.WriteLine(number);
}
await using (var disposableObject = new DisposableObject())
{
//...
}
await using var disposableObject = new DisposableObject();
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)]
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";
List<int> list = null;
// assign if null
list ??= new List<int>();
int? i = null;
i ??= 10;
i ??= 20;
// i == 10;
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
There is already a post about upcoming changes...
https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/
- 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
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