昨日、Connect(); Japan 2018でちょっとだけですけども、C# 8.0の話をしたりしました。 7分(ちょっと超過したけど)だとあんまり大したことを話せず…
とりあえず、昨日やったデモは、1機能1コミットでプルリクを作って GitHub においてあるのでそちらも参照してみてください。
- C# 8.0 デモ用 … 昨日やれたデモ。Preview 1 で入った機能の紹介。
- UfcppSample … C# によるプログラミング入門で書いてるコードに対して NullableReferenceTypes true にするとどうなるか、どう書き換えるかというデモ。時間なかった。
で、今日は、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件ほど。
デリゲートがらみはほんとに鬼門かも…