C#の新機能を使ってコード量を削減する

C#も既に7.0までリリースされ、以前より言語機能が拡張されています。そこで、新しい機能を使って昔ながらのコードを短く簡潔に記述することができるようになりました。

定型的なコードの繰り返しや、コードがごちゃごちゃしている場合に、少しでも短い方が脳に優しいという観点から簡単に使え、それなりにコード削減効果がある機能をいくつか紹介したいと思います。

Null条件演算子を使った判定文の省略

原文では「Null-conditional operators」との事。"?"記号をNull条件演算子として使って評価した左辺がnullでない場合右辺を実行できます。

どういうことかというと、以下のようなイベントがあった場合、

public event EventHandler Updated { get; set; }

今までは、nullかどうかを判定するため、if文をで複数行にまたがっていたコードを書く必要がありました。

// 今までの記述方法
if(this.Updated == null)
{
    return;
}

this.Updated(this, new EventArgs);

それが、新しい書き方では、以下のように1行で表すことができます。

// 新しい書き方
this.Updated?.Invoke(this, new EventArg);

this.Updatedまでがnull出ない場合Ivokeが実行されます。

string文字列の補完機能

stringのプレフィックスに"$"を使用することができるようになり、文字列の結合を"+"以外でも行えるようになりました。

// 今までの書き方
int value = 100;
string message = "Value = " + value.Tostring("00000");

新しい構文では+でつなげる代わりに、プレフィックスに"$"を指定し値を"{値[:書式]}"で指定できます。書式は省略可能なので値だけの指定も大丈夫です。

// 新しい書き方
int value = 100;
string message = $"Value = {value:00000}";

今までのstring.Formatの書き方と同じ効果が$リテラルで得られるます。インラインで書式指定を同時にできるので見た目がすっきりします。

outパラメータをインラインで宣言

outパラメータですが、まず変数を宣言してからout引数を持つメソッドに渡すコードを以下のように書いていましたがこれをインラインで宣言できます。

// 今までの書き方
int result;
if(int.TryParse("10", out result))
{
    Console.WrilteLine("Result = " + result);
}

新しい書き方では事前に変数を宣言する必要が無くなり、outキーワードの後ろに変数宣言ができます。

// 新しい書き方
if(int.TryParse("10", out int result))
{
    Console.WrilteLine($"Result = {result}");
}

is演算子の評価結果をインラインで受ける

本当は"パターンマッチング"というらしいですが、outパラメータと同様に、is演算子の結果を受ける変数をインラインで宣言できます。

今まで、以下のようにis - as変換や、as - nullチェックしていたコードが、

// 今までの書き方
public void F1(Exception ex)
{
    // その(1)
    if(ex is KeyNotFoundException)
    {
        var knfex = ex as KeyNotFoundException;
        
        // knfex変数を使った何らかの処理
    }
    
    // その(2)
    var knfex = ex as KeyNotFoundException
    if(ex != null)
    {
        // knfex変数を使った何らかの処理
    }
}

is演算子の時と同じくインラインで変数を宣言できます。

// 新しい書き方
public void F2(Exception ex)
{
    if(ex is KeyNotFoundException knfex) // 同時に宣言できる
    {
        // knfex変数を使った何らかの処理
    }
}

これを前述のNull条件演算子と組み合わせると、「nullチェックをしつつキャストする」のような複数の条件文が必要な評価を1行で行えます。

if(obj1?.obj2?.ex is KeyNotFoundException knfex)
{
    // 変換が全て成功している時にここに入ってくる
}

余談ですが、定数もis演算子の右辺に指定できるため、以下のような特定の「キャストしつつ特定の値だったとき」の処理も1行で書くことができます。

if(ex is null) { ... }
if(ex is 10) { ... } 

VS2017ではインテリセンスが指摘してくれます

VS2017でC#プログラミングをしている場合、紹介したような新しい記述に置き換えられる「定石コード」を書くと、エディタ上でクイック操作のフォローが表示されます。この時表示される電球マークをクリック(もしくはShift + Alt + F10)するとその場でリファクタリングの候補を出してくれます。また、コードのミニマップをスクロールバーに出している場合、リファクタリング可能な行がある事をハイライトで示してくれます。

もし上記のような仕様を知らずともVSが教えてくれるため、そのような個所でクイック操作の内容を確認してみるとよいかもしれません。(適用してもCtrl + Zでほぼ必ず元に戻せるのでとりあえず適用してもよさそうです。