昨日、Connect(); Japan 2018でちょっとだけですけども、C# 8.0の話をしたりしました。 7分(ちょっと超過したけど)だとあんまり大したことを話せず…

とりあえず、昨日やったデモは、1機能1コミットでプルリクを作って GitHub においてあるのでそちらも参照してみてください。

で、今日は、Visual Studio 2019 Preview 1のその後のピックアップRoslynでパターン マッチングがらみの話が1件と、 機能やれなかったUfcppSampleデモのフォローアップ。

パターン マッチング

v2。

元々あった issueが長大になりすぎたので、今残ってる作業だけを抜き出して新しくissueを立てた模様。

今月1回書いてますけども、 パターン マッチングは Preview 1 に入ると思ってたけど入ってなかったって感じなんですが。 上記 issue はその現状で残ってる課題の一覧。

  • switch 式を、void も認めて、「式ステートメント」も認めたい
    • void M1()void M2() に対して、x switch { 1 => M1(), 2 => M2() }; みたいなのを認めたい
  • switch 式、末尾 , を認めたい
    • 今の実装だと x switch { 1 => M1(), 2 => M2(), } (M2()の後ろの,) を書くとエラー
  • 0, 1要素分解を認めたい
    • if (o is (3) _) みたいなの
    • キャスト+定数パターン o is (int)0 みたいなのとの弁別で悩み中
  • 名前付き引数でのオーバーロード解決を認めるかどうか
    • Deconstruct(int X, int Y)Deconstruct(double Angle, double Length)があるとき、p is (X: 3, Y: 4)で前者を呼べるようにするかどうか
  • プロパティ パターンで、インデクサーとかイベントとかを認めるか
  • ref構造体のトラッキングがバグってる
    • 今、パターン マッチングを使うと、本来返せないはずの Span<T> を返せちゃうバグあり
  • ITupleインターフェイス越しの分解と、Deconstructメソッド越しの分解の優先度をどうするか

UfcppSample に対して NullableReferenceTypes true

null許容参照型は待望の機能なわけですが、 1つ懸念としては、既存コードに対して適用するとどうなるかでしょう。 一応は、既存コードを壊さないようにopt-in (明示的にオプション指定しないと有効にならない)になっているわけですが、 「問答無用に全体に opt-in してしまうとどうなるか」は気になるところだと思います。

ということで、昨日は、時間が許せばC# によるプログラミング入門で書いてるコードに対して opt-in してみる話もしたかったんですが。 特に、うちのサイトは結構 C# 1.0 とか 2.0 の頃からある古いコードも残っていますし。 それに対して opt-in してみようと。

まあ、時間的に無理だったのでここで改めて。

普通な範囲

大半は、「意図して null を受け付けているところにちまちまと ? を付けていく作業になります。

これで、51件あった警告が、28件減って23件に。

ジェネリクス

Preview 1の実装では、結構ジェネリクス周りの実装が抜けています。 これに関しては、最近、Roslyn 上で generics がどうこうみたいなプルリクをよく見かけるので、Preview 2までにはだいぶ改善するかもしれません。

とりあえず、今はあきらめて(Preview 2で良くなることを祈って)、無視します。

基本的に、後置き!演算子を付けると、forgiving (警告もみ消しを容赦してもらう)になります。 ジェネリクスがらみにはこいつを使って対処。

ローカル関数に変更

ラムダ式に対して再帰したり、自分自身を参照したりするとき、以下のように、デリゲートをいったん空初期化した上で改めてラムダ式を代入する必要があります。

Func<int, int> f = null;
f = x => x <= 1 ? 1 : f(x - 1);

この、最初の = null がよくない。

で、これは単に、ラムダ式をローカル関数に書き換えるだけで解消します。

あと片付け

ガベコレで少しでも早く不要メモリを回収してもらうために、もう要らない変数に null を代入することもあったりします。

これに関しては、

  • 要らなくなる(Dispose する)までは絶対に null にならないので、T で使いたい
  • 要らなくなった後だけのために T? に変えるのはちょっと嫌

という感じ…

ちょっと迷ったんですが、結局は ! に頼ることにしました。

バグ

まあ、バグっててどうしようもない奴は #pragma warning disable で黙殺。

バグ報告済みなので、Preview 2までに治ってるといいなぁ…

ちなみに、このバグは Visual Studio 自体を落とします。

static class Ex
{
    // こういう、カリー化デリゲート(拡張メソッドを使ったデリゲート構築)に対する null 検証がバグってる。
    // 非 null なインスタンスを渡していても、なぜか null 警告が出る。
    // バグを黙殺するために ! を付けようとすると Visual Studio が落ちる。
    public static Action a = new object().M;
    public static void M(this object x) { }
}

デモ都合

C# によるプログラミング入門内には、「null がダメなのは百も承知で、もしそれでも null を渡してしまったらどうなるか」を示すデモがいくつかあります。

百も承知でわざとやってるんだからうるせー(おもむろに #pragma warning disable)。

どうしていいのかわからなかった奴…

で、6件ほど、ほんとにどう対処すべきなのかわからなくてとりあえず ! とか #pragma warning disable とかでやっつけたのが6件ほど。

デリゲートがらみはほんとに鬼門かも…