Visual Studio 2019 のバージョンが正式に v16.7 になりました。プレビューを2つ挟んでのアップデートでしたね。
(個人的に)気になっていた機能をいくつか記録しておきます。(詳細は、最後の参考などから確認いただければと思います)
C# のコーディング変更点
1. デバッガ―ディスプレイのショートカットの追加
Ctrl+.
詳細はこれ。
テストコードを書くのもいいけど、実行中のデバッグは、並列処理だと困ることもあるけど、やっぱり強力なのでデバッグしやすくしておく。
2. コード補完機能で日付の書式指定の候補がでる
見たまま。書式指定はかなり忘れっぽかったので、わりと真面目にたすかります。
var time = DateTime.Now; Console.WriteLine($"{time:yyyy-MM-dd}"); Console.WriteLine(time.ToString("yyyy-MM-dd"));
3. Top level statements
これはとても短いコードを書くとき用の機能で、Main メソッドを書かなくてもコンパイルできる仕組みのようです。特殊な予約語として args
で引数にもアクセスできる。(内部的には生成するメソッドが切り替わる)
using system; Console.WriteLine("Top level statements");
[STAThread] のような属性を付与するときは、Main が必要なったりするなど、この機能は、あくまでも簡単なコードを書くためのものとしたほうがいいです。あれこれ求める機能では、そもそもなさそうです。
3.1 Top level statements と Main メソッドがあるときの動作
Top level statements が優先されるみたいです。
4. record 型の追加
record は class や struct に対する修飾子(abstract, sealed, static など)とは違って、新しい型です。(最初は data の修飾子があったようだけど)delegate のようにコード中に浮いたような感じのコードに見えるのですが、以下のとおり。
record Sample(int x, int y); var sample = new Sample(1, 2); Console.WriteLine($"{sample.x}, {sample.y}");
内部的に init アクセサーを利用するようです。
4.1 record のリフレクション
基本的には、書き換え不可の record ですがリフレクションを使うと setter を取得して書き換えできてしまいます。(良い悪いの話では無いおまけ的な話)
public record Record { public int X { get; init; } } var record = new Record(1); var prop = typeof(Record).GetProperty("X"); var setter = prop.GetSetMethod(); setter.Invoke(record, new object[] {2}); Console.WriteLine(record.X); // output 2
4.2 With 式
record 型の with 式を使った呼び出しは、ちょっと特殊なケースになりそうですが、これは non-destructive mutation
(非破壊的な変更)にあたるものだと思います。
var otherSill = personSill with { name = "シィル・プライン (IP)" };
with 式は値の変わらないデータを、既知の値から一部だけ変更して新しいデータを作成するために利用します。なので、with 式を伴った record は、その人のある時点を表現しているのような形になりそうです。
5. init アクセサー (init accessor)
get/set のアクセサーのうち、set
アクセサーを init
にスイッチできます。(set and init を同時に実装できない)
class Sample { public int Data { get; init; } }
プロパティの値を書き換えるために set
アクセサーをつけますが、クラス内だけアクセスがあるときは private set;
にしていたと思います。
そこから、名前のとおり初期化のタイミングだけアクセスを許可するときのために init
が追加された形です。ただ、正確には制限付きの set
アクセサーのようなものなので、次の選択から呼び出せるようです。
- コンストラクターの中
- オブジェクト初期化子
- with 式
- 別の init アクセサーの中
Init
アクセサーが出てきたためにInit
という単語は、暗黙的な初期化の意味が強まった気がしています。私は初期化メソッドの名前をInitialize
にして省略せず書いていたのですが、基本的には初期化のタイミングでだけ呼び出すということなら、Init
のほうが伝わりやすくなったのかもしれないです。
現行の注意として、init を利用するためには、次のコードを追加しないと正しく動きませんでした。見ての通り init を追加する拡張ですね。
// .NET5 で BCL に追加予定。.NET5 でなくても独自に定義することができる。 namespace System.Runtime.CompilerServices { internal class IsExternalInit : Attribute { } }
5.1 init の詳しいところ
実際のところ、init アクセサーは record, class, struct のどの型でも追加することができます。(岩永さんの youtube 参考)
public record Record { public int X { get; init; } } public class Class { public int X { get; init; } } public struct Struct { public int X { get; init; } }
こうなると、record 型を使わなくても init でいいじゃないか、となるのですが、実際は型が持っている Equals
メソッドの動作が異なるようです。
class はインスタンスの一致 (reference equal) を見ますが、record と struct はメンバーの値の一致を見ます。(memberwise equal)
var r1 = new Record{ X = 1 }; var r2 = new Record{ X = 1 }; var c1 = new Class{ X = 1 }; var c2 = new Class{ X = 2 }; Console.WriteLine(r1.Equals(r2)); // True Console.WriteLine(c1.Equals(c2)); // False Console.WriteLine(r1 == r2); // reference equal False
現状は、struct とrecord は同じような動きをしますが、内部的に struct は Runtime の特別な対応でメンバーの一致を調べているので、record と比べて動作が遅いようです。
record と struct はかなり似ているもので、ちょっと class な struct が record くらいの位置になっています。
また、init は IL 上ではなにもしていないので、ただの set です。C# Compiler の段階で処理する機能になっているので、実行時の差は考慮する必要がなさそうです。
6. is 演算子の警告
以下のコードで x is not の形を(間違って)表すことが多かったためみたいです。
実際は C# 8.0 で追加された x!
(null-forgiving) になってしまうので、is 演算子と別のオペレーターとして処理されてしまうようです。(しかも is 演算子は null チェックを含むので無意味という)
public void Sample(object? o) { if (o !is 1) { Console.WriteLine("o is 1"); } throw new Exception("o is not 1"); }
warning IDE0080: Suppression operator has no effect and can be misinterpreted.
サプレッション演算子 (!) は効果がなく、誤解される可能性があります。
XAML の変更点
1. カラーが見えるようになった
これは見ての通り、すぐ気づいた。えらい。
2. XAML のリロードボタンが追加された
これは、以下のショートカットキーがボタンになって追加されたようなものかな。XAML がエラーでクラッシュしたときとかに使えるかも。
参考
- microsoft devblog - Visual Studio 2019 v16.7 and v16.8 Preview 1 Release Today!
- .NET Blog - Welcome to C# 9.0
- 未確認飛行 C - C# 9.0 in Visual Studio 16.7 preview 3
- 作者:BillWagner
- 発売日: 2018/09/05
- メディア: Kindle版
ゼロトラストネットワーク ―境界防御の限界を超えるためのセキュアなシステム設計
- 作者:Evan Gilman,Doug Barth
- 発売日: 2019/10/28
- メディア: 単行本(ソフトカバー)
FACTFULNESS(ファクトフルネス) 10の思い込みを乗り越え、データを基に世界を正しく見る習慣
- 作者:ハンス・ロスリング,オーラ・ロスリング,アンナ・ロスリング・ロンランド
- 発売日: 2019/01/11
- メディア: 単行本