C#-7.0: 滲み出すスコープ
Visual Studio の C# プロジェクトでも Error
も Warning
も1件も見逃さない綺麗なビルドを心掛けていますが、 Messages
は見落としていました。何件か来ている。
まず、一番上を見る。 IDE0018: Variable declaration can be inlined
とやら。
C#-7.0 で何がどう変わるかを眺めた際に「うへー」って気持ちになった事があったのを思い出してしまいました。
// C# < 7.0 { var a = "1.23"; double b; // <-- 事前に宣言が必要 var c = double.TryParse( a, out b ); Console.WriteLine( $"{a} {b} {c}" ); } // C# >= 7.0 { var a = "2.34"; //double b; <-- 要らんくなった var c = double.TryParse( a, out double b ); // <-- out の後で変数宣言していた事にできる言語機能 Console.WriteLine( $"{a} {b} {c}" ); }
↑手間がかからず一見便利に見えますが、「スコープが滲み出す」とタイトルに書いたような現象が起こるようになります↓
var a = "3.45"; if ( double.TryParse( a, out double b ) ) Console.WriteLine( $"X: {a} {b}" ); // <-- ここで b が生きているのは感覚的にもまあわかる Console.WriteLine( $"Y: {a} {b}" ); // <-- コンパイル可能、実行可能、 b はここでも生きている
きもぃ。便利さと拮抗する程度には十分にきもぃ😅
この言語仕様上のスコープがプログラマーのソースコード・リーディングにおける視認のスコープ感と明らかに異なるだろう挙動には注意が必要になる。
var p = "3.45"; var q = "4.56"; if ( double.TryParse( p, out double buffer ) ) Console.WriteLine( buffer ); if ( double.TryParse( q, out double buffer ) ) // <-- コンパイル不能 Console.WriteLine( buffer );
プログラマー、特に C 系に近い言語を主戦場とするプログラマーにとって、このコードはコンパイル可能な気がすると思います。しかし、 C#-7.0 言語仕様では "正しく" コンパイル不能なコードです。 p
のパースの際に out
に続けて宣言した double buffer
のスコープは if
と同じスコープになります。 if
の内部でだけ使えるような見栄えのソースコードですが、 if
と同じスコープへと double buffer
変数のスコープは "染み出し" しています。
同様の現象は is
でも発生します。
var n = new List< int >(){ 1,2,3 }; var m = Enumerable.Range( 10, 20 ); if ( n is IEnumerable< int > integers ) Console.WriteLine( integers.Count() ); if ( m is IEnumerable< int > integers ) // <-- コンパイル不能 Console.WriteLine( integers.Count() );
染み出しスコープ言語機能…きもぃ😂 便利なのはワカルけど、どうして if スコープへ束縛とか考えなかったんだろう、言語仕様作った人。
おまけ
他にも Messages
は出ているので一応おまけメモ。
IDE0033 Prefer explicitly provided tuple element name
↑は↓のようなタプルに名前が付けられる場合にもタプル標準の Item1
とか使っていると出る。
var vs = new List< string >(){ "aaa", "bbb", "ccc" }; // ↓の t.Item1 に対して IDE0033 が発生する var xs = ( from v in vs select ( v, v.GetHashCode() ) ).ToDictionary( t => t.Item1, t => t.Item2 ); Console.Write( string.Join( "\n", xs ) );
しかし、このしれっとタプルの変数名を勝手に変更してくれちゃう機能は C#-7.1 かららしい。 .net Framework 4.7.2 とかのプロジェクトでは使えない。 .net Core 2.0 ≃ C# 7.1 らしい。 IDE のおすすめメッセージは良い機能とは思うものの、プロジェクトが使用可能な言語バージョンを超えるサジェストはどうかと思う😂
IDE0042 Test C# Variable declaration can be deconstructed
↑は↓のようなタプルを構造化束縛せずに使っている場合に発生する。
var vs = new ( string uni, int tako )[] { ( "きたむらさき", 123 ) , ( "えぞばふん", 234 ) , ( "あか", 345 ) }; // ↓タプルを構造化束縛せずに使うと IDE0042 foreach ( var t in patterns ) Console.WriteLine( $"uni={t.uni} tako={t.tako}" ); // ↓構造化束縛して使うと出ない foreach ( var ( uni, tako ) in patterns ) Console.WriteLine( $"uni={uni} tako={tako}" );