Skip to main content
C# 8 in Libraries and
Applications
Christian Nagel
https://csharp.christiannagel.com
Topics
NEW C# 8 FEATURES HOW TO USE C# 8 IN
LIBRARIES AND
APPLICATIONS
GUIDELINES
Christian Nagel
• Training
• Coaching
• Consulting
• Development
• Microsoft MVP
• www.cninnovation.com
• csharp.christiannagel.com
• github.com/cninnovation
How to use C# 8
How to use C# 8
• By default enabled with
.NET Core 3.0
• Enable with other projects
• <LangVersion>8.0</LangVersion>
• <Nullable>enable</Nullable>
• Directory.Build.Props
Features based on
Frameworks/Runtimes
• Syntax Sugar Features mit allen Frameworks
• Manche Features brauchen Klassen &
Interfaces
• Ranges, async streams
• Runtime Updates Required
• .NET Standard 2.1
• Default Interface Members
Default Interface Members
Default
Interface
Members -
Overview
• Interfaces mit Implementierung
• Modifiers: private, protected, internal, public,
virtual, abstract, override, sealed, static, extern
Default Interface Methods
Ändern von Interfaces
ohne Breaking
Changes
1
Traits –
Wiederverwendbarkeit
von Methoden in
unabhängigen Klassen
2
Basiert auf Java's
Default Methods
3
Default Interface Methods
• Changing the interface without breaking changes
public interface ILogger
{
void Log(string message);
}
public interface Ilogger
{
void Log(string message);
void Log(Exception ex) => Log(ex.Message);
}
public class MyLogger : ILogger
{
public void Log(string message) => Console.WriteLine(message);
}
Demo
• Default Interface Members
• Interface mit breaking change
• Interface mit non-breaking change
• Traits
Tipps
Ist die erste Version eines Interfaces
komplett?
Erweiterungen sind jetzt möglich!
Alternative zu Extension Methoden
Runtime-Erweiterungen!
Indices and Ranges
Indexes and Ranges
Index und
Range &
Types &
Extensions
New
Operators
• ^ Hat Operator
• .. Range
Operator
Hat Operator
int[] arr = { 1, 2, 3 };
int lastItem = arr[^1];
Range
string text1 = "the quick brown fox jumped over the lazy dogs";
string quick = text1[4..9];
string dog = text1[^4..^1];
string brownfoxjumpedandmore = text1[10..];
string thequick = text1[..8];
string text2 = text1[..];
Demo
• Ranges and Indices
• Access Slice of Span<T>
• Access String
• Range, Index Types
• Custom Collections
Implicit
Support
Index
•countable (Length, Count)
•instance indexer with int
Range
•countable
•Slice method with two int
Nullable Reference Types
Null References
Most common .NET Exception
NullReferenceException
Billion Dollar Mistake
1965 in Algol by Tony Hoare "Billion Dollar Mistake"
Null Conditional Operator (C# 6)
• Null checks made easier
int? length = customers?.Length;
Customer first = customers?[0];
int? count = customers?[0]?.Orders?.Count();
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Coalescing Operator (C# 5)
• Default values for null
int length = customers?.Length ?? 0;
public bool CanExecute(object parameter) =>
_canExecute?.Invoke() ?? true;
Reference
Types are not
Nullable
• #nullable enable/disable/restore
• annotated with ? – nullable reference type
• string?
• Null-forgiving operator
• !
• Null-coalescing assignment
• numbers ??= new List<string>();
Nullable Reference Types
• Dokumentation: null oder nicht null
• Hilft finden von Bugs, aber keine Garantie!
• Flow analysis - tracks nullable reference variables
• Breaks existing code (opt-in)
• Nullability implemented with metadata (ignored by
downlevel compilers)
• string, T non-nullable
• string?, T? nullable
Demo
• Nullable Reference Types
• Enable nullability
• Add annotations
• Solving issues
• Current issues
Guidelines
• Library authors – Nullable adoption phase before
.NET 5
• App developers – nullability on your own pace
• Annotate new APIs
• Do not remove argument validation
• Parameter is non-nullable if parameters are
checked (ArgumentNullException)
• Parameter is nullable if documented to accept null
• Prefer nullable over non-nullable with
disagreements
Async Streams
Async
Streams
bis jetzt: async/await liefert ein Ergebnis
Async Streams erweitert async/await mit
Stream von Ergebnissen
Asynchronous Datenquellen die vom
Consumer kontrolliert werden
Alternative zu System.Reactive
Async Streams
• IAsyncDisposable
• IAsyncEnumerable
• IAsyncEnumerator
public interface IAsyncDisposable
{
ValueTask DisposeAsync();
}
public interface IAsyncEnumerable<out T>
{
IAsyncEnumerator<T> GetAsyncEnumerator();
}
public interface IAsyncEnumerator<out T> :
IAsyncDisposable
{
ValueTask<bool> MoveNextAsync();
T Current { get; }
}
Using Async Streams
• await foreach
IAsyncEnumerator<T> enumerator =
enumerable.GetAsyncEnumerator();
try
{
while (await enumerator.MoveNextAsync())
{
Use(enumerator.Current);
}
}
finally
{
await enumerator.DisposeAsync();
}
await foreach (var i in enumerable)
{
Use(i);
}
Async with yield
• return IAsyncEnumerable static async IAsyncEnumerable<int> MyIterator()
{
try
{
for (int i = 0; i < 100; i++)
{
await Task.Delay(1000);
yield return i;
}
}
finally
{
await Task.Delay(200);
Console.WriteLine("finally");
}
}
Demo
• Async Streams & SignalR
• Streaming from the Server to the
Client
• Streaming from the Client to the
Server
• C# 8 Async Streams
More Features…
using declaration
public void Method(IEnumerable<string> lines)
{
using var file = new StreamWriter("sample.txt");
foreach (var line in lines)
{
file.WriteLine(line);
}
}
switch Expression
static string M2(Shape shape) =>
shape switch
{
Shape s when s.Size.height > 100 =>
$"large shape with size {s.Size} at position {s.Position}",
Ellipse e =>
$"Ellipse with size {e.Size} at position {e.Position}",
Rectangle r =>
$"Rectangle with size {r.Size} at position {r.Position}",
_ => "another shape"
}
};
Recursive, Property, and Discard Patterns
static string M3(Shape shape) =>
shape switch
{
CombinedShape (var shape1, var (pos, _)) =>
$"combined shape - shape1: {shape1.Name}, pos of shape2: {pos}",
{ Size: (200, 200), Position: var pos } =>
$"shape with size 200x200 at position {pos.x}:{pos.y}",
Ellipse (var pos, var size) =>
$"Ellipse with size {size} at position {pos}",
Rectangle (_, var size) => $"Rectangle with size {size}",
_ => "another shape"
};
Demo
• Switch expressions with tuples
• Pattern matching
Summary
Avoid Errors
Better Productivity
Better Performance
Questions?
For action
• Annotate libraries with nullability
• Use new C# 8 features
• https://csharp.christiannagel.com
• https://github.com/cninnovation
• https://github.com/ProfessionalCSharp
Thank you!