読者です 読者をやめる 読者になる 読者になる

ぺやろぐ

ゲームと奈々ちゃんと時々プログラミング

〔C#〕 nameof演算子が使えないけど、似たようなことをする(プロパティ名の取得)

C# 技術

nameof演算子は便利だねってお話。

目的

C# 5.0以下の環境でnameof演算子と似たようなものを実装する。
改めてnameof演算子っていいよねって気付く。

経緯

WPFの実装中、

private string name_;
/// <summary>
/// 名前
/// </summary>
public string Name
{
    get { return name_; }
    set
    {
        if (name_!= value)
        {
            name_= value;
            NotifyPropertyChanged("Name");
        }
    }
}

と文字列でNotifyPropertyChangedに引数を渡しています。
これ、プロパティ名を変更しても文字列は変更対象にならないので、ここの変更忘れが原因で動かなくなるってことが起きるんですよね。
まぁ、そこまで気づきにくい場所でもないのですがちょっと鬱陶しいですね。

登場! nameof演算子

とか思っていると、C#6.0でnameof演算子が追加され、以下のように書くことができるようになりました。

private string name_;
/// <summary>
/// 名前
/// </summary>
public string Name
{
    get { return name_; }
    set
    {
        if (name_!= value)
        {
            name_= value;
            NotifyPropertyChanged(nameof(Name));
        }
    }
}

nameof(プロパティ名))
たったこれだけの記述にするだけで変更がかかるようになり、つまらないミスをなくすことができるんですね。

これは素晴らしい。

いや、ほんと。

ですが、C#6.0の環境じゃないと使えない。

会社の環境によって使えるときと使えないときがあるんですよね。

「まぁ、その時は文字列でいいんじゃない?」って思ってしまいますがあえてnameof演算子と似たようなことができるようにがんばりましょう。

実装

以下、コード

今回使用するメソッドの定義

using System.Linq.Expressions;

    static class PropertyGet
    {
        /// <summary>
        /// プロパティ名を取得する
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="e"></param>
        /// <returns></returns>
        public static string GetPropertyName<T>(Expression<Func<T>> e)
        {
            var memberEx = (MemberExpression)e.Body;
            return memberEx.Member.Name;
        }
    }

WPFでの使用例
MainWindow.xaml.cs

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MainViewModel();
    }

MainViewModel.cs

    public MainViewModel()
    {
        strChange = new RelayCommand(StrChange);
    }

    public ICommand strChange
    {
        get; private set;
    }

    private string str_;
    /// <summary>
    /// 文字列
    /// </summary>
    public string Str
    {
        get
        {
            return str_;
        }
        set
        {
            if (str_ != value)
            {
                str_ = value;
                // ここでさきほど定義したGetPropertyNameメソッドの呼び出し(戻り値がプロパティ名)
                NotifyPropertyChanged(PropertyGet.GetPropertyName(()=> Str));
            }
        }
    }

    /// <summary>
    /// PropertyChangedの実装
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(info));
    }

    private void StrChange()
    {
        Str = "名前を取得できているからこれが表示される";
    }

起動時はこちら
f:id:peyangu485:20160124185218p:plain

ボタン押下で
f:id:peyangu485:20160124185223p:plain

きちんと変更通知がわたっているので、文字列が表示されていますね。

まとめ

さすがにnameof演算子ほど短く、とは言えないですがそこそこいいんじゃないかと。
短くしたい場合は、クラス名とメソッド名をもっと簡略化すればいいかな。

どちらでも使えるようにしておきましょー。