++C++; // 未確認飛行 C ブログ

http://ufcpp.net/

INotifyPropertyChanged の実装

with 3 comments

追記: 色々更新した

前々から気になってはいたんだけども。

今の C# だと、手書きだけで INotifyPropertyChanged の実装をうまくやろうと頑張るのは厳しいと思うんですよね。コードスニペット使うのを前提に考えるのが一番いい妥協だと思います。

ということで、以下のようなものを作成。

  • ヘルパークラス(C#)
    • とりあえず同じプロジェクトにぶち込むなりライブラリ化するなり
  • コードスニペット
    • マイドキュメントの下の、Visual Studio のフォルダー以下、Code SnippetsVisual C#My Code Snippets にコピって置いてください

あとは、propnotify ってタイピングしてタブを押して、型名とプロパティ名を打つだけ。

例:

例えば、以下のような感じ(青いところがコードスニペットで生成した部分)になります。

public class CodeSnipet前提な実装 : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string Name
    {
        get { return _fieldName; }
        set
        {
            if (_fieldName == value) return;
            _fieldName = value;
            PropertyChanged.Raise(this, PropertyNameName);
        }
    }

    private string _fieldName;
    private string _propertyNameName;
    private string PropertyNameName
    {
        get
        {
            if (_propertyNameName == null)
                _propertyNameName = PropertyChangedEventHandleExtensions.PropertyName(() => Name);
            return _propertyNameName;
        }
    }
}

public static partial class PropertyChangedEventHandleExtensions
{
    public static string PropertyName<T>(Expression<Func<T>> property)
    {
        var memberExp = property.Body as MemberExpression;
        if (memberExp == null)
        {
            throw new ArgumentException();
        }

        var senderExp = memberExp.Expression as ConstantExpression;
        if (senderExp == null)
        {
            throw new ArgumentException();
        }

        return memberExp.Member.Name;
    }

    public static void Raise(this PropertyChangedEventHandler handler, object sender, params string[] propertyNames)
    {
        if (handler == null)
        {
            return;
        }

        foreach (var name in propertyNames)
        {
            handler(sender, new PropertyChangedEventArgs(name));
        }
    }
}

ポイント

  • コードスニペットにしておけば、タイピング量は大したことない
    • 上のコードでいうと、string と Name しか打たない
  • プロパティ名はキャッシュしておく
    • 式木操作は結構重たいんで、毎回 exp.Member.Name を取得するのは避けたい
    • これを避けるだけで、普通の実装とほとんど変わらない性能が出る
  • コードスニペット使うのに OnPropertyChanged(“Name”) にしない理由
    • 文字列にしちゃうと、Name をリネームしても "Name" の部分は書き換わってくれない
    • C# の場合、ツールサポートが最大限得られるように作るのが一番実入りいい
      • なので、() => Name から式木経由でプロパティ名を取るのはなかなかいい案だと思う
  • Raise の propertyName は params にして複数受け取れるようにした方がいいかも
    • 1つ更新されたときに、他のプロパティ値も一緒に変化する場合も結構あるんで

Written by ufcpp

2009年12月28日 @ 03:00

カテゴリー: 未分類

3件のフィードバック

Subscribe to comments with RSS.

  1. タイプ量は減るけどコード量が結構増えてるのは、ちょっといけてないかな。とは思います。自分は、前に私のBlogでも書いたPostSharpを使ってやってます。最近はSilverlightにもPostSharpが対応したので、ほぼすべて、これでかけるかな?一応、記事にしてもみました。 http://bit.ly/7K1eoM

    zio3

    2009年12月28日 at 07:45

  2. AOP は見えないところで処理をされすぎるのが嫌なんですよねぇ。Python の decorator でやな思いもしてるんで、attribute/annotation 的なものに具体的な処理を入れてしまうのにはちょっと抵抗が強いです。あと、プロパティ更新通知は、微妙に定型文じゃなくてカスタマイズしたい場合があって、そういうときに、ソースが出てないとちょっと。というので、コード量増やす方向に傾くのはやむなしかなぁという気が最近強まっています。

    信之

    2009年12月28日 at 16:03

  3. […] #INotifyPropertyChanged の実装 « ++C++; // 未確認飛行 C ブログ Share:はてブ続きLike this:Like一番乗りで「Like」しませんか。 カテゴリー: C#, EF ← EF:連関エンティティはedmではアソシエーションとして表される […]


コメントを残す