C# ist eine Programmiersprache mehrerer Paradigmen. C# war nie rein objektorientiert, schon in der ersten Version als Component-basierte Sprache angepriesen. Mit der Zeit gab es Erweiterungen der deklarativen Programmierung, und auch funktionale Konzepte wurden bei C# übernommen. In welche Richtung entwickelt sich C# weiter? In dieser Session werden neueste Erweiterungen von C# gezeigt. Themen sind dabei die letzten aktuellen Änderungen sowie geplante Erweiterungen wie z. B. die Vermeidung von NullReferenceException mit Non-Nullable Reference Types und die Reduktion von Garbage-Collector-Aufrufen mit Hilfe von Memory-Optimierungen.
15. 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;
16. Deconstruction (7.0)
• Create parts 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
• 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;
19. 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;
}
20. 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 };
21. C# 7 Point Releases
• Sicherer, effizienter Code
• Mehr Freiheiten
• Weniger Code
30. 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
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
Index und
Range &
Extensions
New
Operators
• ^ Hat Operator
• .. Range
Operator
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 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"
}
};
40. 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"
};
41. Null References
Most common .NET Exception
NullReferenceException
Billion Dollar Mistake
1965 in Algol by Tony Hoare "Billion Dollar Mistake"
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
• 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
45. 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
}
46. 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
47. 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
//...
49. Compatibility
• Enable this in 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