C# nameofの使い方は?

こんにちは!トミセンです。

あまり使う機会がないと思われているnameof式ですが、

「C#でnameofって、使う意味あるの?」
「C#でnameofって、どうやって使うの?」

実は便利なコーディング手法なんですが、いまいち使いどころに迷ってしまいがちです。

今回はそんなお悩みを解決します。
ずばり!「C# nameofの使い方」についてご紹介します。

それでは一緒に学んでいきましょう!

目次

C# nameofの使い方

まず、結論から。

文字列を指定する場面でnameofを使うことで、コードの修正漏れを防ぎ保守性の高いコードにすることができます。

実際に有効なケースを見ていきましょう。

nameof 演算子の対応バージョン
C# 6.0 以降(Visual Studio 2015 以降)

nameofを使わないソース

/// <summary>
/// モデル
/// </summary>
public class AmountModel
{
    ///<summary>コード</summary>
    public int Code { get; set; }

    ///<summary>税抜き額</summary>
    public decimal Amount1 { get; set; }

    ///<summary>税額</summary>
    public decimal Amount2 { get; set; }
}


public class Test
{
    public void Main()
    {
        // データ作成
        var amountModel = new AmountModel { Code = 1111, Amount1 = 3000m, Amount2 = 300m };

        // 税込み額計算
        var amount = Calculate(amountModel);

        // 結果
        Console.WriteLine($"税込み額:{amount.ToString()}");
		
        // 結果出力
        // 税込み額:3300
    }

    /// <summary>
    /// 計算
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public decimal Calculate<T>(T obj)
    {
        decimal amount = 0m;

        Type type = typeof(T);
        foreach (PropertyInfo property in type.GetProperties())
        {
            switch (property.Name)
            {
                case "Amount1":
                case "Amount2":
                    amount += (decimal)type.GetProperty(property.Name).GetValue(obj, null);
                    break;
                default:
                    break;
            }
        }

        return amount;
    }
}	

実行すると、税込み額:3300が表示されます。

処理内容はAmountModelの項目のAmount1Amount2を足して、税込み額を表示しています。

コードとコメントだけでは分かりにくい部分があるので、ポイントを絞ってコードを解説していきます!

計算する項目かどうかの判断にはまず、対象項目かの判定が必要になります。

その判定をしているのが次の場所になります。

public decimal Calculate<T>(T obj)
{
    foreach (PropertyInfo property in type.GetProperties())
    {
        switch (property.Name)
        {
            case "Amount1":
            case "Amount2":
                amount += (decimal)type.GetProperty(property.Name).GetValue(obj, null);
                break;
            default:
                break;
        }
    }
}	

ここでは、クラスのプロパティ情報を取得して、項目名が文字列“Amount1”または“Amount2”の場合は、項目の値を取得し変数に値を足していきます。

ポイントは項目名を文字列で指定しているというところです。

現段階では文字列で指定しても問題はありません。

でもソースコードは変更されていきます。次のコードをみてください。

※通常はこんな面倒な方法で計算はしないと思いますが、説明のために作ったコードですので突っ込みはご遠慮ください。

/// <summary>
/// モデル
/// </summary>
public class AmountModel
{
    ///<summary>コード</summary>
    public int Code { get; set; }

    ///<summary>税抜き額</summary>
    public decimal TaxExcluded { get; set; }

    ///<summary>税額</summary>
    public decimal TaxAmount { get; set; }
}


public class Test
{
    public void Main()
    {
        // データ作成
        var amountModel = new AmountModel { Code = 1111, TaxExcluded = 3000m, TaxAmount = 300m };

        // 税込み額計算
        var amount = Calculate(amountModel);

        // 結果
        Console.WriteLine($"税込み額:{amount.ToString()}");
		
        // 結果出力
        // 税込み額:0
    }

    /// <summary>
    /// 計算
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public decimal Calculate<T>(T obj)
    {
        decimal amount = 0m;

        Type type = typeof(T);
        foreach (PropertyInfo property in type.GetProperties())
        {
            switch (property.Name)
            {
                case "Amount1":
                case "Amount2":
                    amount += (decimal)type.GetProperty(property.Name).GetValue(obj, null);
                    break;
                default:
                    break;
            }
        }

        return amount;
    }
}	

変更された内容が、分かったでしょうか?

そうです。AmountModelのメンバが変更されています。

誰かが分かりにくいと指摘したのでしょう。Amount1Amount2が、TaxExcludedTaxAmountというに変更されています。

ここで問題発生してしまいました。

var amountModel = new AmountModel { Code = 1111, TaxExcluded = 3000m, TaxAmount = 300m };

コンパイルエラーになるAmountModelの生成箇所は変更されましたが、金額計算をしているCalculateメソッドのswitch文はAmount1Amount2のままです。

そのため、実行すると、税込み額:0が表示されます。

1人で開発しているなら、Calculateメソッドも対象だとすぐに気づいたでしょう。

でも1人の人がそのシステムをずっと担当するなんてことはありません。

他の人が関われば漏れてしまう場合もあります。では、どうすればよかったのでしょうか。

ここでnameofが活躍します。

nameofを使ったソース

switch (property.Name)
{
    case nameof(AmountModel.Amount1):
    case nameof(AmountModel.Amount2):
        amount += (decimal)type.GetProperty(property.Name).GetValue(obj, null);
        break;
    default:
        break;
}	

switch文でnameofを使っていれば、問題を発見することができていたはずです。

使い方はnameof(AmountModel.Amount1)のようにnameof(クラス名.メンバ名)のように書きます。

意味は、"Amount1"と書いたのと同じですが、AmountModelからAmount1がなくなるとコンパイルエラーを表示してくれます。

Visual Stuioの実際の画面です。

C# nameof

エラーになっているのが確認できると思います。もちろんビルドも通りません。

つまり、変更によるバグに気づかずにリリースしてしまうというようなことがなくなります。

以上が、nameofの使い方です。

その役割は、コードの修正漏れを防ぎ保守性の高いコードにすることです。

まとめ

保守性の高いコードは重要ですよね。

それでは、また。

よかったらシェアしてね!
目次
閉じる