C# - what's new with C# 7, what's planned with C# 8: productivity, performance, avoiding errors with tuples, pattern matching, nullable reference types, and more
1. C# - What's Next?
Christian Nagel
csharp.christiannagel.com
2. Goals
• Wie entwickelt sich C#?
• Versionen
• C# Current (C# 7.x)
• Future Plans
• Constraints
• Einige Features können jetzt schon verwendet werden
• Etwas wird sich noch ändern
4. Christian Nagel
• Training
• Coaching
• Consulting
• Microsoft MVP
• www.cninnovation.com
• csharp.christiannagel.com
5.
6. Expressions Everywhere (C# 7.0)
• Property Accessors
• Constructors
• Destructors
• Event Accessors
• Local Functions
private string _firstName;
public string FirstName
{
get => _firstName;
set => Set(ref _firstName, value);
}
7. Out Vars (C# 7.0)
• Declare variable on use
string n = "42";
if (string.TryParse(n, out var result)
{
Console.WriteLine(
$"Converting to a number was successful: {result}");
}
8. Non-Trailing Named Arguments (C# 7.2)
• Assign the name to any argument
if (Enum.TryParse(weekdayRecommendation.Entity, ignoreCase: true,
out DayOfWeek weekday))
{
reservation.Weekday = weekday;
}
9. Local Functions (C# 7.0)
• Declare functions within methods
• Scope within the method
• Simplifies Lambda syntax
• Helps with parameter checking (yield)
public void SomeFunStuff()
{
int add(int x, int y) => x + y;
int result = add(38, 4);
Console.WriteLine(result);
}
public void SomeFunStuff()
{
Func<int, int, int> add = (x, y) => x + y;
int result = add(38, 4);
Console.WriteLine(result);
}
10. Throw Expressions (C# 7.0)
• Throw in expressions instead of statements
private readonly IBooksService _booksService;
public BookController(BooksService booksService)
{
if (booksService == null)
{
throw new ArgumentNullException(nameof(b));
}
_booksService = booksService;
}
private readonly IBooksService _booksService;
public BookController(BooksService booksService)
{
_booksService = booksService ?? throw new ArgumentNullException(nameof(b));
}
11. Tuples (C# 7.0)
• Combine multiple values
• Strong names
• Value types
var t1 = (n: 42, s: "magic");
int i1 = t1.n;
string s1 = t1.s;
12. Infer Tuple Names (C# 7.1)
• Infer tuple names from parameters
• Similar to anonymous types
var t1 = (racer.FirstName, racer.Wins);
int wins = t1.Wins;
13. Deconstruction (C# 7.0)
• Create parts from objects or tuples
• Implement Deconstruct Method
var p1 = new Person("Tom", "Turbo");
(string firstName, string lastName) = p1;
14. Pattern Matching (C# 7.0)
• is Operator and switch statement extended
• Const Pattern
• Type Pattern
• Var Pattern
public void IsSample(object o)
{
if (o is 42)
{
}
if (o is Person p)
{
}
if (o is var v1)
{
}
}
public void PatternMatchingWithSwitchStatement(object o)
{
switch (o)
{
case 42:
break;
case Person p when p.FirstName == "Katharina":
break;
case Person p:
break;
case var v:
break;
}
}
15. Records (C# 8.0 - Planned)
• Immutable Type
• class or struct
public struct Pair(object First, object Second);
var p1 = new Pair("one", "two");
var p2 = p1.With(First: "alpha");
16. Record Implementation (C# 8.0 - Planned)
• Implements
• IEquatable
• GetHashCode
• Deconstruct
• With
public struct Pair(object First, object Second);
public struct Pair : IEquatable<Pair>
{
public object First { get; }
public object Second { get; }
public Pair(object First, object Second)
{
this.First = First;
this.Second = Second;
}
public bool Equals(Pair other) =>
Equals(First, other.First) && Equals(Second, other.Second);
public override bool Equals(object other) =>
(other as Pair)?.Equals(this) == true;
public override int GetHashCode() =>
(First?.GetHashCode()*17 + Second?.GetHashCode()).GetValueOrDefault();
public Pair With(object First = this.First, object Second = this.Second) =>
new Pair(First, Second);
public void Deconstruct(out object First, out object Second)
{
First = this.First;
Second = this.Second;
}
}
var p1 = new Pair("one", "two");
var p2 = p1.With(First: "alpha");
17. Productivity - Summary
• Expressions everywhere
• Out vars
• Non-trailing named arguments
• Local functions
• Throw expressions
• Tuples
• Pattern matching
• Records
23. ArrayPool
• Reduce work needed by Garbage Collector
• Pool of arrays managed by ArrayPool
int[] arr = ArrayPool<int>.Shared.Rent(length);
//... use array
ArrayPool<int>.Shared.Return(arr, clearArray: true);
24. Reference Semantics
• Reference Types
• class
• Copy By Reference
• Use Managed Heap
• Value Types
• struct
• Copy By Value
• Use Stack or Managed Heap (Boxing)
• GC doesn't need to cleanup the stack
25. Pass Value Type by…
• by value
• by reference
• by readonly reference
• C# 7.2
public void SetItem(int makeACopy)
{
}
public void SetItem(ref int byReference)
{
byReference = 42;
}
public void SetItem(in int byReference)
{
// guarantee no change
}
26. Returning Value Types By Reference
• ref return (7.0)
• ref local (7.0)
• ref readonly return (7.2)
• ref readonly local (7.2)
public ref int GetItem(int index)
{
return ref _items[index];
}
public ref readonly int GetReadonlyItem(int index)
{
return ref _items[index];
}
ref int x = ref GetItem(4);
27. .NET Type Categories
• Managed Heap
• class
• Stack or Managed Heap
• struct
• Stack Only (C# 7.2)
• ref struct
28. Span
• Accesses range of native memory, managed heap, stack
• Continous range of memory
• Reference semantics
• Specialized for arrays, strings
string text = GetString();
ReadOnlySpan<char> span1 = text.AsSpan();
ReadOnlySpan<char> slice1 = span1.Slice(5, 20);
string newString = new string(slice1.ToArray());
29. Overloads Span and Memory
• Parse
• System.Random
• System.Text.StringBuilder
• System.Net.Sockets
• Specialized extension methods
for arrays and strings
public virtual ValueTask<int> ReadAsync(
Memory<byte> destination,
CancellationToken cancellationToken = default);
30. Slicing (ranges) – C# 7.3 Planned
• Operator ..
var slice = source[5..10];
switch (codePoint)
{
case 1536..1541:
break;
foreach (var item in 3..5)
{
31. Performance - Summary
• Reduce copy needs with value types
• Reduce need for unsafe code
• Span
• ArrayPool
37. Declare Nullable Reference Types
• Default to non-nullable
• ? to make reference type nullable
class Book
{
public Book(string title, string? isbn = null)
{
Title = title;
Isbn = isbn;
}
public string Title; // not null
public string? Isbn; // may be null
}
38. Using nullable reference type
void M1(string? ns)
{
Console.WriteLine(ns.Length); // compiler warning
void M2(string? ns)
{
if (ns == null) throw new ArgumentNullException(nameof(ns));
Console.WriteLine(ns.Length); // ok, not null
ns = null;
Console.WriteLine(ns.Length); // compiler warning
void M3(string? ns)
{
if (ns != null)
{
Console.WriteLine(ns.Length); // ok
39. Using non-nullable reference type
void M1(string ns)
{
Console.WriteLine(ns.Length); // ok
void M2(Book b)
{
b.Title = null; // warning
string isbn = b.Isbn; // warning – may be null
string title = b.Title; // ok
43. More Information (1)
• https://dot.net
• https://github.com/dotnet/csharplang
• Sample Code:
• https://github.com/CNinnovation
44. More Information (2)
• https://github.com/ProfessionalCSharp
• https://csharp.christiannagel.com
• https://www.cninnovation.com
• Training & Coaching