C#CallerMemberNameの特性の紹介とInotifyPropertyChangedの実現の簡略化

5345 ワード

目次
 
一.CallerMemberNameプロパティの説明
二.CallerMemberName InotifyPropertyChangeのシンプル化

一.CallerMemberNameプロパティの説明


開発中に、次の関数などの呼び出し情報を記録する必要がある場合があります.
        public void DoSomething()
        {
            TraceMessage(" !");
        }

テストデバッグを容易にするために、イベント情報のほかに、イベントのコードの場所や呼び出し情報も知りたいです.C++では、マクロで__を通過するマクロを定義できます.FILE__および_LINE__をクリックして現在のコードの場所を取得しますが、C#はマクロをサポートしていません.このような機能を実現するのは面倒です.この問題に対して、Net 4.5には、CallerMemberName、CallerFilePath、CallerLineNumberの3つのAttributeが導入されています.コンパイラの協力の下で、呼び出し関数(正確にはメンバー)の名前、呼び出しファイル、呼び出し行番号をそれぞれ取得できます.上記のTraceMessage関数は次のように実現できます.
        public static void TraceMessage(string message,
            [CallerMemberName] string memberName="",
            [CallerFilePath] string sourceFilePath="",
            [CallerLineNumber] int sourceLineNumber=0)
        {
            Console.WriteLine($"message:{message}
member name: {memberName}" + $"
source file path: {sourceFilePath}
source line number: {sourceLineNumber}"); }

呼び出しの結果は次のとおりです.
message: !
member name: DoSomething
source file path: /Users/qinyuanlong/DotNet_core_x1/CallerMemberNameConsole/CallerMemberNameConsole/Program.cs
source line number: 16

また、コンストラクション関数、コンストラクション関数、属性などの特殊な場所でCallerMemberName属性にマークされている関数を呼び出すと、取得した値が異なり、その値は次の表のようになります.
呼び出し先
CallerMemberNameが取得した結果
メソッド、プロパティ、またはイベント
メソッド、プロパティまたはイベントの名前
コンストラクタ
文字列".ctor"
せいてきこうぞうかんすう
文字列".cctor"
こうぞうかんすう
この文字列「Finalize」
ユーザー定義の演算子または変換
生成された名前メンバー、たとえば「op_Addition」.
とくせいこうぞうかんすう
プロパティに適用されるメンバーの名前

二.CallerMemberName InotifyPropertyChangeのシンプル化


WPFでは、MVVMを使用して通常のオブジェクトのプロパティをバインドする場合、インタフェースでプロパティ変更の通知を取得する必要があります.一般的にクラスを新規作成し、InotifyPropertyChangeインタフェースを継承します.
class NotifyObject : INotifyPropertyChanged
    {
        private int number;
        public int Number
        {
            get { return number; }
            set { number = value; OnPropertyChanged("Number"); }
        }

        private string text;
        public string Text
        {
            get { return text; }
            set { text = value; OnPropertyChanged("Text"); }
        }


        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName = "")
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

このようにすると、文字列のハードコーディングで属性名が渡され、スペルミスや再構築コードでこの文字列を更新するのを忘れた場合、インタフェースで更新が得られないという大きな危険があります.(ハードコーディングで両者の整合性を保証するのは頼りにならない行為です)
ちょうど上のプロパティが実装できます.
class NotifyObject : INotifyPropertyChanged
    {
        private int number;
        public int Number
        {
            get { return number; }
            set { number = value; OnPropertyChanged(); }
        }

        private string text;
        public string Text
        {
            get { return text; }
            set { text = value; OnPropertyChanged(); }
        }


        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

新しいOnpertyChangeEventHandlerで[CallerMemberName]属性でパラメータを修飾すると、ある属性が変更されるとこの関数が呼び出され、propertyNameにはその属性の名前が付いているので、前と同じ機能を実現しますが、入力属性名を表示する必要はありません.
属性が多いとコードが煩雑になります.ここには共通点の関数を書いて彼らを統一して、次は直接使うことができます.C#の文法の制限のため、クラスの外部でeventを呼び出すことができなくて、そのため拡張方法を書くことができなくて、ここで簡単に1つのオブジェクトを書くことができて、次回は直接変更しました:
class NotifyObject : INotifyPropertyChanged
    {
        private int number;
        public int Number
        {
            get { return number; }
            set { UpdateProper(ref number, value); }
        }

        private string text;
        public string Text
        {
            get { return text; }
            set { UpdateProper(ref text, value); }
        }

        protected void UpdateProper(ref T properValue, T newValue, [CallerMemberName] string properName = "")
        {
            if (object.Equals(properValue, newValue))
                return;

            properValue = newValue;
            OnPropertyChanged(properName);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

本稿ではブログ参照:C#5.0新特性学習のCallerMemberName,CallerMemberNameを用いてInotifyPropertyChangedの実装を簡略化