私事ですが、今後C#やることになっておりまして。以前以下の記事を書いたのですが、だいたいでC#5.0あたりで知識は途絶えています。
この記事3年前か…
最近C#やってないなーということで、どういう風に変わったのか追ってみようと思っています。
参照サイト
ここは公式を見ましょう。
こういうページがあるのはすごいですね。私のように、久々にC#やる人にやさしいです。
範囲
C#6.0
以降から見ていきます。async
等は一応理解しているつもりです。学習はやり直しますが、紹介はしません。
6.0以降全部まとめて書くと、文章量がすさまじいことになることが分かったので、バージョンごとに記事分けます。
C#バージョン6.0
静的インポート
static
で公開されているメンバーを使用する場合に、名前空間とクラス名をusing
句で記載することで、呼び出し時のクラス名を省略できる機能です。
using system System.Console; // これで呼べるようになる。 WriteLine("Hello world!"); // 無いとこうなる Console.WriteLine("Hello world!");
何度もstaticメンバーを呼び出すときに、コード全体が短くすっきり書けるので便利ですね。
例外フィルター
catch
句で例外をキャッチする条件を付与できる機能です。サンプルそのまま貼り付けます。
public static async Task<string> MakeRequest() { WebRequestHandler webRequestHandler = new WebRequestHandler(); webRequestHandler.AllowAutoRedirect = false; using (HttpClient client = new HttpClient(webRequestHandler)) { var stringTask = client.GetStringAsync("https://docs.microsoft.com/en-us/dotnet/about/"); try { var responseText = await stringTask; return responseText; } catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301")) { return "Site Moved"; } } }
これは、catch
の中で分岐するのか外で分岐するのかの違いですね。自作例外の場合は、例外クラス自体を分けたほうが良いでしょう。例のように、HTTPレスポンスコードによって処理を分けたい場合に便利です。ネストが浅くなるのがよさそう。when
というキーワードが増えたんですね。
自動プロパティ初期化子
public string Status { get; } = "init";
以前だとこういう書き方になります。
public string Status { get { return "init"; } }
return
が省略できるの良いですね。
式形式のメンバー
public string DisplayStatus => $"{Status.ToUpper()}";
関数やプロパティをラムダ式で書ける、という変更のようです。これは楽。単一の式であるステートメントをこれで書けると。普通はブロックつくってreturn
で返す、という形ですが、一文であれば式の戻り値をそのまま返してくれるんですね。
Null 伝達子
Person person = null; // person is nullになる var name = person?.Name ?? "person is null";
nullの可能性がある変数に?
を付けることで、メンバーにアクセスした場合もnullが返るようになる、という機能です。
これが氾濫するソースは読みたくないですね…ScalaのOption.getOrElse
みたいなものですが、構文レベルじゃなくて新しいクラス導入するとかでもいいとは思います。気軽に書けすぎちゃうのは怖いです。
if (person == null)
みたいなのがネストしていくよりはマシ、というのは事実です。
文字列補間
上でしれっと書きました。$
を文字列の前につけると、{
と}
に囲まれた部分に式を書けるようになる機能です。最近は多くの言語に導入されていますね。
public string Greeting(User user) => $"ようこそ {user?.Name?? "ゲスト"} さん";
string.Format
の、文字列中の括弧の数と引数の数が一致していないと例外が発生する問題が発生しなくなるのは大きいですし、可読性の観点でも非常に良いですね。
nameof 演算子
これはWPFとかやっていた人には朗報だった記憶があります。私も喜びました。
string name = "My Name"; // name と出力 Console.WriteLine(nameof(name));
nameof
に渡したメンバー名や変数名を文字列で返す、という機能です。データバインドで値変えたことを通知するためにプロパティ名が必要、というときに、型安全にどうやって対処するのか回避策がいろいろ採られていたのですが、nameof
が来たのでほとんどが不要になりました。
あとは、例示の通り例外メッセージで変数名をメッセージに入れるときも、安全に行えます。
インデックス初期化子
var dict = new Dictionary<int, string> { [1] = "apple", [2] = "orange };
Dictionary
への値設定は、
dict[1] = "apple";
のようにできるので、それを初期化時もできるようにしたよ、という構文のようです。なるほど。ちょっと便利。
読み取り専用の自動プロパティ
public string FirstName { get; }
という宣言に対して、コンストラクタ内のみで初期化を許可する、というプロパティです。以前だと
public string FirstName { get; private set; }
と書くと外部から読み取り専用プロパティとして宣言できましたが、クラス内のどこからでもsetできる状態になります。それが良い場合もあるので、用途次第ですね。インスタンスの不変性をより確保できる感じです。
Catch ブロックと Finally ブロックでの Await
C#5.0まではサポートされていなかった部分だけどサポートされたよ、というやつです。内部実装の改善で実現されたものと思われます*1。
現行の例外があった場合、その例外は失われます。
という記述がある通り、catch
で実行した非同期処理でさらに例外が発生させた場合の動作についても記載あるので、慎重に使いましょうね、とのことです。はい。こういうのは慎重に使う以外の対策無いですよね。ちゃんと挙動を把握することが大事ですね。
おわりに
C#は、短くかけることを重点的にやっている気がします。そこが好きです。
C#7.0についても記事書きました。
*1:こういう改訂は過去にもあった気がする