バグの例1: defaultリテラル(C# 7.1)voidM(int? x = default) { }int?の規定値はnullなので、当然、nullであるべき• VS 15.3(リリース時点) : 0になってた• VS 15.4(修正版) : nullに
36.
バグの例2: in引数(C# 7.2)//2変数、既定値付きstatic void M(in int x = 0, in int y = 0) => WriteLine(y);// 1変数だけ値を渡すstatic void Main() => M(1);yには0が入ってほしい• VS 15.5(リリース時点) : なぜかnull参照例外発生• VS 15.6で修正
37.
バグの例2: in引数(C# 7.2)classX{// クラスに対して in 引数static void S(in X x) => WriteLine(x.ToString());// in 引数相手に this を渡すvoid M() => S(this);}• VS 15.5(リリース時点) :ExecutionEngineException発生• VS 15.6(修正版)で修正
C# 7.0struct A{int[]array;ref int First => ref array[0];}unsafe struct B{int* pointer;ref int First => ref pointer[0];}戻り値を参照にできるunsafeなものも返せるref int M(ref int x) => ref x;ref int N(){int x = 0;return ref x;}外からもらったものは返せる中のものは返せない
C# 7.3: オーバーロード解決の改善staticvoid M<T>(this T x) where T : class { }static void M<T>(this ref T x) where T : struct { }static void X(string s, int i){s.M();i.M();}前までは呼び分けできなかった型制約違い
52.
C# 7.3: ジェネリック型制約の追加staticvoid E<T>(this T x)where T : System.Enum { }static void D<T>(this T x)where T : System.Delegate { }static void U<T>(this T x)where T : unmanaged { }列挙型だけを受け付けるデリゲート型だけを受け付けるポインター化可能な型だけを受け付ける
C# 8.0: null許容参照型intM(string s){return s.Length;}int N(string? s){var x = s.Length;if (s == null) return -1;return s.Length;}単にこう書くと非null参照型でも、?でnull許容にnullチェックがないので警告nullチェックより後なのでOK既存コードを壊さないために• オプションでモード切替可能に• null、非null、「未指定」• 既存コードは「未指定」扱いでコード解析する
56.
C# 8.0: 再帰パターンintM(object obj){switch (obj){case int i: return i;case string s: return s.Length;case Point (var x, var y): return x * y;case Point { X : var x, Y : var y }: return X * Y;}throw new IndexOutOfRangeException();}int M(object obj)=> obj switch{case int i => i,case string s => s.Length,case Point (var x, var y) => x * y,case Point { X : var x, Y : var y } => X * Y,_ => throw new IndexOutOfRangeException()};switch式