C# - What’s next?
@christiannagel
https://csharp.christiannagel.com
C# Strategie
Laufende Erweiterungen
Geänderte Bedürfnisse erfüllen
Agenda
C#
Strategie
C# Today C# Soon
Christian Nagel
• Training
• Coaching
• Consulting
• Development
• Microsoft MVP
• www.cninnovation.com
• csharp.christiannagel.com
Schnell Innovationen einführen
Aber im Geist von C#
Ziele mit C# 7.1, 7.2, 7.3
Sicherer, effizienter Code
•Garbage Collection vermeiden
•Kopieren vermeiden
•"Safe" Code
1
Mehr Freiheiten
•Zusätzliche Möglichkeiten
2
Weniger Code
•"Sag es kürzer"
3
C# 8
Magisch
C# 7.x Today
C# 7.0
Tuples &
Deconstruction
Pattern
Matching
Expressions
everywhere
Reference
Semantics
Tuples (7.0)
• Werte unterschiedlicher Typen
kombinieren
• Strong Names
• Value Types var t1 = (n: 42, s: "magic");
int i1 = t1.n;
string s1 = t1.s;
Deconstruction (7.0)
• Create parts from objects or tuples
• Implement method Deconstruct
var p1 = new Person("Tom", "Turbo");
(string firstName, string lastName) = p1;
Pattern Matching (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;
}
}
C# 7.1
• Async main
• Generics pattern match
• Infer tuple names
• Target typed default
static async Task Main()
{
await FooAsync();
}
public void Send<T>(T packet)
where T : Packet
{
if (packet is KeepalivePacket keepalive)
{
}
var t1 = (racer.FirstName, racer.Wins);
int wins = t1.Wins;
ImmutableArray<int> arr = default(ImmutableArray<int>);ImmutableArray<int> arr = default;
C# 7.2
• Leading Separator
• Non-trailing named arguments
• private protected
• Conditional Ref
• readonly ref
• Span Safety
ushort b1 = 0b_1010_1111_0101_0000;
if (Enum.TryParse(day, ignoreCase: true,
out DayOfWeek weekday))
{
reservation.Weekday = weekday;
}
C# 7.3
• Auto Property Field Attributes
• Generic constraints
• unmanaged, Enum, Delegate
• Expression Variables in Initializers
• Pattern-based fixed statement
• Ref local reassignment
• Stackalloc array initializers
[Serializable]
public class Foo
{
[field: NonSerialized]
public string MySecret { get; set; }
}
void Hash<T>(T value) where T : unmanaged
{
}
var d1 = stackalloc int[3] { 1, 2, 3 };
var d2 = stackalloc int[] { 1, 2, 3 };
var d3 = stackalloc[] { 1, 2, 3 };
C# 7 Point Releases
• Sicherer, effizienter Code
• Mehr Freiheiten
• Weniger Code
C# 8
Smallish Features (1)
• Default literal deconstruction (implemented)
• Alternative interpolated verbatim strings (VS Preview)
(int i, string j) = (default, default); // C# 7
(int i, string j) = default; // C# 8
var foo = $@"c:foo{someFile}"; // C# 7
var foo = @$"c:foo{someFile}"; // C# 8
Smallish Features (2)
• Generic attributes
• in-progress
• Relax ordering ref and partial modifiers
• in-progress
• Null coalescing assignment
• VS Preview
public class ValidationAttribute<T> : Attribute
{
}
if (variable == null) // C# 7
{
variable = expression;
}
Variable ??= expression; // C# 8
public ref partial class { } // C# 7
public partial ref class { } // C# 8
Smallish Features (3)
• Caller expression attribute
• prototype
• Target-typed new
• prototype
• Pattern-based using
• VS Preview
• using declarations
• VS Preview
// C# 7
private Dictionary<string, List<int>> field =
new Dictionary<string, List<int>>()
{
{ "item1", new int[] { 1, 2, 3 } }
};
// C# 8
private Dictionary<string, List<int>> field =
new()
{
{ "item1", new() { 1, 2, 3 } }
};
public static class Debug
{
public static void Assert(bool condition,
[CallerArgumentExpression("condition")] string message = null);
}
Debug.Assert(array.Length == 1);
Debug.Assert(array.Length == 1, "array.Length == 1");
Default Interface Methods (Prototype)
Ä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);
}
Default Interface
Methods
Allowed Modifiers
private, protected, internal, public, virtual,
abstract, override, sealed, static, extern
Default Interface Methods
Mehrfachvererbung mit Interfaces?
interface I0
{
void M() => Console.WriteLine("I0");
}
interface I2 : I0
{
override void M() => Console.WriteLine("I2");
}
interface I1 : I0
{
override void M() => Console.WriteLine("I1");
}
interface I3 : I1, I2
{
void I0.M() => I2.base.M();
}
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
• Verfügbar in Visual Studio 2019
Preview
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
• foreach await
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");
}
}
Indexes and Ranges
Index und
Range &
Extensions
New
Operators
• ^ Hat Operator
• .. Range
Operator
Hat Operator
int[] arr = { 1, 2, 3 };
int lastItem = arr[^1];
Slice
string text1 = "the quick brown fox jumped over the lazy dogs";
string text2 = text1[4..8];
string text3 = text1[^4..^1];
string text4 = text1[10..];
string text5 = text1[..8];
string text6 = text1[..];
Patterns Extended
Discard Pattern
• Always match
1
Property
Pattern
• Match für
Property Werte
2
Recursive
Pattern
• Match für innere
Properties
3
switch
Expression
• Moderner switch
Syntax
4
Pattern Matching Now (7.x)
static string M1(Shape shape)
{
switch (shape)
{
case Shape s when s.Size.height > 100:
return $"large shape with size {s.Size} at position {s.Position}";
case Ellipse e:
return $"Ellipse with size {e.Size} at position {e.Position}";
case Rectangle r:
return $"Rectangle with size {r.Size} at position {r.Position}";
default:
return "another shape";
}
}
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"
};
Null References
Most common .NET Exception
NullReferenceException
Billion Dollar Mistake
1965 in Algol by Tony Hoare "Billion Dollar Mistake"
Null Conditional Operator (C# 6)
• Reduce Null-Checks
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;
Nullable Reference
Types
• 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
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
}
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
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
//...
null forgiveness operator
void M3(Book book)
{
string publisher = book.Publisher!;
//...
}
Compatibility
• Enable this in your own speed
• Project
• NullableContextOptions
• File Scope
• #nullable enable
• #nullable disable
• #nullable safeonly
• #nullable restore
Issues
• Code-changes erforderlich
• Non-nullable müssen im Constructor initialisiert werden
• Applikationen umstellen, auch wenn die Library noch nicht so weit ist
• Größere Vorteile erst wenn Libraries auch umgestellt wurden
• Es gibt noch Issues
• z.B. Generics mit Value & Reference Types
Summary
C# 8
Nullable
Reference
Types
1
Indexes and
Ranges
2
Async Streams
3
Magic
4
Questions?
Try it out!
• Visual Studio 2019 Preview – Side by side
• https://visualstudio.microsoft.com/vs/preview/
More Information
• https://github.com/ProfessionalCSharp
• https://github.com/CNinnovation
• https://csharp.christiannagel.com
• https://www.cninnovation.com
• Training & Coaching
Thank you!

C# What's next? (7.x and 8.0)

  • 1.
    C# - What’snext? @christiannagel https://csharp.christiannagel.com
  • 2.
  • 4.
  • 5.
  • 6.
    Christian Nagel • Training •Coaching • Consulting • Development • Microsoft MVP • www.cninnovation.com • csharp.christiannagel.com
  • 8.
  • 11.
    Ziele mit C#7.1, 7.2, 7.3 Sicherer, effizienter Code •Garbage Collection vermeiden •Kopieren vermeiden •"Safe" Code 1 Mehr Freiheiten •Zusätzliche Möglichkeiten 2 Weniger Code •"Sag es kürzer" 3
  • 12.
  • 13.
  • 14.
  • 15.
    Tuples (7.0) • Werteunterschiedlicher Typen kombinieren • Strong Names • Value Types var t1 = (n: 42, s: "magic"); int i1 = t1.n; string s1 = t1.s;
  • 16.
    Deconstruction (7.0) • Createparts from objects or tuples • Implement method Deconstruct var p1 = new Person("Tom", "Turbo"); (string firstName, string lastName) = p1;
  • 17.
    Pattern Matching (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; } }
  • 18.
    C# 7.1 • Asyncmain • Generics pattern match • Infer tuple names • Target typed default static async Task Main() { await FooAsync(); } public void Send<T>(T packet) where T : Packet { if (packet is KeepalivePacket keepalive) { } var t1 = (racer.FirstName, racer.Wins); int wins = t1.Wins; ImmutableArray<int> arr = default(ImmutableArray<int>);ImmutableArray<int> arr = default;
  • 19.
    C# 7.2 • LeadingSeparator • Non-trailing named arguments • private protected • Conditional Ref • readonly ref • Span Safety ushort b1 = 0b_1010_1111_0101_0000; if (Enum.TryParse(day, ignoreCase: true, out DayOfWeek weekday)) { reservation.Weekday = weekday; }
  • 20.
    C# 7.3 • AutoProperty Field Attributes • Generic constraints • unmanaged, Enum, Delegate • Expression Variables in Initializers • Pattern-based fixed statement • Ref local reassignment • Stackalloc array initializers [Serializable] public class Foo { [field: NonSerialized] public string MySecret { get; set; } } void Hash<T>(T value) where T : unmanaged { } var d1 = stackalloc int[3] { 1, 2, 3 }; var d2 = stackalloc int[] { 1, 2, 3 }; var d3 = stackalloc[] { 1, 2, 3 };
  • 21.
    C# 7 PointReleases • Sicherer, effizienter Code • Mehr Freiheiten • Weniger Code
  • 22.
  • 23.
    Smallish Features (1) •Default literal deconstruction (implemented) • Alternative interpolated verbatim strings (VS Preview) (int i, string j) = (default, default); // C# 7 (int i, string j) = default; // C# 8 var foo = $@"c:foo{someFile}"; // C# 7 var foo = @$"c:foo{someFile}"; // C# 8
  • 24.
    Smallish Features (2) •Generic attributes • in-progress • Relax ordering ref and partial modifiers • in-progress • Null coalescing assignment • VS Preview public class ValidationAttribute<T> : Attribute { } if (variable == null) // C# 7 { variable = expression; } Variable ??= expression; // C# 8 public ref partial class { } // C# 7 public partial ref class { } // C# 8
  • 25.
    Smallish Features (3) •Caller expression attribute • prototype • Target-typed new • prototype • Pattern-based using • VS Preview • using declarations • VS Preview // C# 7 private Dictionary<string, List<int>> field = new Dictionary<string, List<int>>() { { "item1", new int[] { 1, 2, 3 } } }; // C# 8 private Dictionary<string, List<int>> field = new() { { "item1", new() { 1, 2, 3 } } }; public static class Debug { public static void Assert(bool condition, [CallerArgumentExpression("condition")] string message = null); } Debug.Assert(array.Length == 1); Debug.Assert(array.Length == 1, "array.Length == 1");
  • 26.
    Default Interface Methods(Prototype) Ändern von Interfaces ohne Breaking Changes 1 Traits – Wiederverwendbarkeit von Methoden in unabhängigen Klassen 2 Basiert auf Java's Default Methods 3
  • 27.
    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); }
  • 28.
    Default Interface Methods Allowed Modifiers private,protected, internal, public, virtual, abstract, override, sealed, static, extern
  • 29.
    Default Interface Methods Mehrfachvererbungmit Interfaces? interface I0 { void M() => Console.WriteLine("I0"); } interface I2 : I0 { override void M() => Console.WriteLine("I2"); } interface I1 : I0 { override void M() => Console.WriteLine("I1"); } interface I3 : I1, I2 { void I0.M() => I2.base.M(); }
  • 30.
    Async Streams • bisjetzt: 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 • Verfügbar in Visual Studio 2019 Preview
  • 31.
    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; } }
  • 32.
    Using Async Streams •foreach await 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); }
  • 33.
    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"); } }
  • 34.
    Indexes and Ranges Indexund Range & Extensions New Operators • ^ Hat Operator • .. Range Operator
  • 35.
    Hat Operator int[] arr= { 1, 2, 3 }; int lastItem = arr[^1];
  • 36.
    Slice string text1 ="the quick brown fox jumped over the lazy dogs"; string text2 = text1[4..8]; string text3 = text1[^4..^1]; string text4 = text1[10..]; string text5 = text1[..8]; string text6 = text1[..];
  • 37.
    Patterns Extended Discard Pattern •Always match 1 Property Pattern • Match für Property Werte 2 Recursive Pattern • Match für innere Properties 3 switch Expression • Moderner switch Syntax 4
  • 38.
    Pattern Matching Now(7.x) static string M1(Shape shape) { switch (shape) { case Shape s when s.Size.height > 100: return $"large shape with size {s.Size} at position {s.Position}"; case Ellipse e: return $"Ellipse with size {e.Size} at position {e.Position}"; case Rectangle r: return $"Rectangle with size {r.Size} at position {r.Position}"; default: return "another shape"; } }
  • 39.
    switch Expression static stringM2(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" } };
  • 40.
    Recursive, Property, andDiscard 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" };
  • 41.
    Null References Most common.NET Exception NullReferenceException Billion Dollar Mistake 1965 in Algol by Tony Hoare "Billion Dollar Mistake"
  • 42.
    Null Conditional Operator(C# 6) • Reduce Null-Checks 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));
  • 43.
    Coalescing Operator (C#5) • Default values for null int length = customers?.Length ?? 0; public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
  • 44.
    Nullable Reference Types • Hilftfinden 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
  • 45.
    Declare Nullable ReferenceTypes • 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 }
  • 46.
    Using nullable referencetype 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
  • 47.
    Using non-nullable referencetype 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 //...
  • 48.
    null forgiveness operator voidM3(Book book) { string publisher = book.Publisher!; //... }
  • 49.
    Compatibility • Enable thisin your own speed • Project • NullableContextOptions • File Scope • #nullable enable • #nullable disable • #nullable safeonly • #nullable restore
  • 50.
    Issues • Code-changes erforderlich •Non-nullable müssen im Constructor initialisiert werden • Applikationen umstellen, auch wenn die Library noch nicht so weit ist • Größere Vorteile erst wenn Libraries auch umgestellt wurden • Es gibt noch Issues • z.B. Generics mit Value & Reference Types
  • 51.
  • 52.
  • 53.
    Try it out! •Visual Studio 2019 Preview – Side by side • https://visualstudio.microsoft.com/vs/preview/
  • 54.
    More Information • https://github.com/ProfessionalCSharp •https://github.com/CNinnovation • https://csharp.christiannagel.com • https://www.cninnovation.com • Training & Coaching
  • 56.