「バグでしょ?」からの「仕様です」が2件ほど。
そしてだいたいこの手の話題は、5・6年前に Stack Overflow で話題が出てて、 Eric Lippertが回答済みという落ち。
&& の後ろ
Change to definitive assignment in LINQ queries #4509
dynamic
が絡んだ時に、以下のコードで、「b が未初期化の可能性があります」エラーになるという話。
decimal.TryParse(v, out a) && decimal.TryParse("15", out b) && a <= b
TryParse(v, out a)
でa
が初期化されるTryParse(v, out b)
でb
が初期化されるa <= b
でそのa
とb
を使う
dynamic
が絡まなければ、TryParse
の戻り値は bool
で確定していてます。
そして、bool
の &&
であれば、1., 2. が評価された後でしか 3. が評価されない保証があるのでエラーは起こしません。
が、ユーザー定義型で、ユーザー定義の true
, false
&
演算子を用意していると、2. をすっ飛ばして3. が評価される場合があり得るというのがエラーの原因。dynamic
が絡むと、戻り値も dynamic
なわけで、bool
に確定しない。そうなると、2. がすっ飛ばされる可能性があって、3. の時点で 'b' が初期化されいている保証が取れないという状態。
配列の共変性
Invalid optimization performed by C# compiler for IEnumerable
以下のコードで b
は false
enum Enum0 { First }
enum Enum1 { First }
var source = new Enum0[3];
...
bool b = source is IEnumerable<Enum1>;
これが、いったん object
で受けるように変更するだけで b
が true
になる。
object source = new Enum0[3];
bool b = source is IEnumerable<Enum1>;
なんか変じゃない?という話。
1個目は、C# のルールで型判定していて false
。
2個目は、object
を挟んだことで C# 上は判定せず、実行時に CLR が型判定するようになって、
CLR のルールでは true
になる。
ということみたい。
配列は、ジェネリックがない頃に無理やり特殊対応な共変性を実装してるので、なんか微妙に変な挙動をすることがあったり。