微软 Mads Torgersen《以Null的处理、回调地狱的应对为例,看C#背后的问题解决思路》

Mads在微软担任C#编程语言的Program Manager,负责C#的设计流程,维护语言规范。在微软12年,他参与了C# 5个版本的设计。也是TypeScript、Visual Basic、Roslyn和LINQ等语言和技术的贡献者。 在加入微软之前,曾在大学担任教职,研究编程语言设计,对Java泛型也有所贡献。
展开查看详情

1.Herding Nulls and other C# stories from the future Mads Torgersen, C# lead designer Microsoft

2. Chapter One Herding nulls

3.Every reference type allows null! Code must be defensive about it C# shares this with most object oriented languages

4.Not all languages have this problem! Differentiate between nullable and non-nullable Use pattern matching to conditionally “unpack” nullables

5.1. Expression of intent 2. Enforcement of intent Within an existing language!

6.public class Person { public string FirstName { get; set; } public string MiddleName { get; set; } public string LastName { get; set; } }

7.public class Person { public string! FirstName { get; set; } } public string? MiddleName { get; set; } public string! LastName { get; set; } L

8.public class Person { public string! FirstName { get; set; } } public string MiddleName { get; set; } public string! LastName { get; set; } L

9.public class Person { public string FirstName { get; set; } } public string? MiddleName { get; set; } public string LastName { get; set; } J

10.1. Protect non-null types from nulls 2. Protect nulls from dereference

11.Must be optional Turn it on when you’re ready to know Can’t affect semantics - warnings, not errors

12.Must do a good job with existing code Can’t force you to rewrite good code Recognize existing ways of ensuring null safety (checks and assignments)

13.Can’t be exhaustive Tradeoff between completeness and convenience

14. Color illustration Nullable reference types

15. Chapter Two Async streams

16. Chapter Three Extension everything

17.extension Student extends Person { // static field static Dictionary<Person, Professor> enrollees = new Dictionary<Person, Professor>(); // 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); } }

18.extension Student extends Person { // static field static Dictionary<Person, Professor> enrollees = new Dictionary<Person, Professor>(); // 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); } } Person mads = new Person("Mads Torgersen", tonyHoare);

19.extension Student extends Person { // static field static Dictionary<Person, Professor> enrollees = new Dictionary<Person, Professor>(); // 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); } } Person mads = new Person("Mads Torgersen", tonyHoare); WriteLine(mads.Supervisor);

20.extension Student extends Person { // static field static Dictionary<Person, Professor> enrollees = new Dictionary<Person, Professor>(); // 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); } } Person mads = new Person("Mads Torgersen", tonyHoare); WriteLine(mads.Supervisor); var tonysStudents = from s in Person.Students where s.Supervisor == tonyHoare select s.Name;

21.extension Student extends Person { // static field static Dictionary<Person, Professor> enrollees = new Dictionary<Person, Professor>(); // 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); } } class Professor { … } interface IStudent { string Name { get; } Professor? Supervisor { get; } void Enroll(Professor supervisor); }

22.extension Student extends Person : IStudent { // static field static Dictionary<Person, Professor> enrollees = new Dictionary<Person, Professor>(); // 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); } } class Professor { … } interface IStudent { string Name { get; } Professor? Supervisor { get; } void Enroll(Professor supervisor); }

23.extension Student extends Person : IStudent { // static field static Dictionary<Person, Professor> enrollees = new Dictionary<Person, Professor>(); // 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); } } class Professor { … } interface IStudent { string Name { get; } Professor? Supervisor { get; } void Enroll(Professor supervisor); }

24.extension Student extends Person : IStudent { // static field static Dictionary<Person, Professor> enrollees = new Dictionary<Person, Professor>(); // 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); } } class Professor { … } interface IStudent { string Name { get; } Professor? Supervisor { get; } void Enroll(Professor supervisor); }

25.interface IGroup<T> { static T Zero { get; } static T operator +(T t1, T t2); } extension IntGroup extends int : IGroup<int> { public static int T Zero => 0; } public static T AddAll<T>(T[] ts) where T : IGroup<T> { T result = T.Zero; foreach (T t in ts) { result += t; } return result; } int sixtyThree = AddAll(new [] { 1, 2, 4, 8, 16, 32 });

26.docs.microsoft.com/dotnet/csharp blogs.msdn.microsoft.com/dotnet github.com/dotnet/csharplang