C # 7, 8, and beyond: language features from design to release to IDE support Kevin Pilch kevinpi@microsoft.com @Pilchie
Stack Overflow - most popular technologies http://stackoverflow.com/insights/survey/2017#most-popular-technologies
Stack Overflow - most loved technologies http://stackoverflow.com/insights/survey/2017#most-loved-dreaded-and-wanted
Changing the tune - Why you can use C# Run on Windows Black box compilers Edit in Visual Studio Proprietary Run everywhere Open compiler APIs Use your favorite editor Open source
C# everywhere - Xamarin
C# everywhere - Unity
C# everywhere -.NET Core
Roslyn the C# language engine There should need to be only one code base in the world for understanding C#
OmniSharp edit C# everywhere
C# Evolution A balancing act Aggressively improve Attractive to new users Embrace new paradigms Stay simple Improve existing development Stay true to the spirit of C#
C# - evolution C# 7 C# 1 C# 2 Generics C# 3 Queries, Lambdas C# 4 Dynamic, Concurrency C# 5 Async C# 6 Eliminate ceremony Work with data Hello World
C# 6 - recap Expression bodied members String Interpolation Conditional access operator nameof Using static Exception Filters Interactive window
Demo: C# 7.0
C# 7.0 what s new static void Main(string[] args) { object[] numbers = { 0b1, 0b10, new object[] { 0b100, 0b1000 }, // binary literals 0b1_0000, 0b10_0000 }; // digit separators } var (sum, count) = Tally(numbers); WriteLine($"Sum: {sum}, Count: {count}"); // deconstruction static (int sum, int count) Tally(object[] values) { var r = (s: 0, c: 0); void Add(int s, int c) { r.s += s, r.c += c; } // tuple types // tuple literals // local functions } return r;
C# 7.0 what s new static (int sum, int count) Tally(object[] values) { var r = (s: 0, c: 0); void Add(int s, int c) { r.s += s, r.c += c; } foreach (var v in values) { switch (v) { case int i: Add(i, 1); break; case object[] a when a.length > 0: var t = Tally(a); Add(t.sum, t.count); break; } } return r; } // tuple types // tuple literals // local functions // switch on any value // type patterns // case conditions
Binary literals Digit separators Tuples Patterns Local functions Tasklike async methods Out var ref locals and returns Throw expressions More expression bodied members C# 7.0 what s new
C# 7.1 introducing point releases default expressions Async main Infer tuple names Reference assemblies
C# 7.2, 8.0, long term thinking ref readonly blittable Interior pointer (needed for Span<T>) Nullable Reference Types Default Interface methods
Nullable and non-nullable reference types string? n; // Nullable reference type string s; // Non-nullable reference type n = null; // Sure; it's nullable s = null; // Warning! Shouldn t be null! s = n; // Warning! Really! WriteLine(s.Length); // Sure; it s not null WriteLine(n.Length); // Warning! Could be null! if (n!= null) { WriteLine(n.Length); } // Sure; you checked WriteLine(n!.Length); // Ok, if you insist!
Default implementations public interface IEnumerator { object Current { get; } bool MoveNext(); void Reset() => throw new InvalidOperationException("Reset not supported"); } public interface IEnumerator<out T> : IDisposable, IEnumerator { new T Current { get; } object IEnumerator.Current => Current; }
C# 8.0, long term thinking Extension Everything Async Streams and Disposables More patterns: recursive, tuples, expressions, etc Records Discriminated Unions Creating Immutable objects
Extension everything extension Enrollee extends Person { // static field static Dictionary<Person, Professor> enrollees = new(); // instance method public void Enroll(Professor supervisor) { enrollees[this] = supervisor; } // instance property public Professor Supervisor => enrollees.trygetvalue(this, out var supervisor)? supervisor : null; // static property public static ICollection<Person> Students => enrollees.keys; } // instance constructor public Person(string name, Professor supervisor) : this(name) { this.enroll(supervisor); }
Async streams and disposables IAsyncEnumerable<Person> people = database.getpeopleasync(); foreach await (var person in people) { // use person } using await (IAsyncDisposable resource = await store.getrecordasync( )) { // use resource }
Recursive patterns if (o is Point(_, var y)) { WriteLine($"Y: {y}"); } if (o is Point { Y: var y }) { WriteLine($"Y: {y}"); }
Pattern matching expressions var s = match (o) { }; int i case Point(int x, int y) string s when s.length > 0 => s, null _ => $"Number {i}", => $"({x},{y})", => "<null>", => "<other>"
Tuples in patterns state = match (state, request) { } (Closed, Open) (Closed, Lock) => Opened, => Locked, (Opened, Close) => Closed, (Locked, Unlock) => Closed, _ => throw new InvalidOperationException( )
Records and discriminated unions record Person(string First, string Last); class Person : IEquatable<Person> { public string First { get; } public string Last { get; } public Person(string First, string Last) { this.first = First; this.last = Last; } public void Deconstruct(out string first, out string last){ first = First; last = Last; } public bool Equals(Person other) => other!= null && First == other.first && Last == other.last; } public override bool Equals(object obj) => obj is Person other? Equals(other) : false; public override int GetHashCode() => GreatHashFunction(First, Last);
Creating immutable objects var p1 = new Point { X = 3, Y = 7 }; var p2 = p1 with { X = -p1.x };
Questions and resources? Language Implementation Reference Contact Content Me https://github.com/dotnet/csharplang https://github.com/dotnet/roslyn http://source.roslyn.io https://twitter.com/roslyn https://github.com/pilchie/qconsp/ kevinpi@microsoft.com @Pilchie Twitter/GitHub