2010年になってから6日もたって初のBlog更新になります。新年あけましておめでとうございます。今年も、マイペースですが試したことや、思ったこと、後ほんの少しの日常を綴っていこうと思います。
今年もよろしくお願いします。
さて、今回の記事のネタは以下の記事が元になってます。
ネタ元記事
- いけてるINotifyPropertyChangedの実装は、結構遅かった
意外というか予想より、はるかに遅かったINotifyPropertyChangedのPropertyChangedイベントの発行処理ですが、コメントに
ななしさんのコメントから引用 -- senderはこれでも取得できるみたいです。 var sender = senderExpression.Value; デバッグ実行で表示される値を眺めてて見つけました。
とのタレコミがありました。多謝です!!ConstantExpressionは、Valueプロパティで値がとれるということみたいです。
MSDNにも
表された式の値に等しい Object。
と説明にあるのでDelegateに変換してDynamicInvokeするまでもなかったみたいです。
ということで、改良版のPropertyChangedEventHandlerExtensionsは以下のようになります。
public static class PropertyChangedEventHandlerExtensions { /// <summary> /// イベントを発行する /// </summary> /// <typeparam name="TResult">プロパティの型</typeparam> /// <param name="_this">イベントハンドラ</param> /// <param name="propertyName">プロパティ名を表すExpression。() => Nameのように指定する。</param> public static void Raise<TResult>(this PropertyChangedEventHandler _this, Expression<Func<TResult>> propertyName) { // ハンドラに何も登録されていない場合は何もしない if (_this == null) return; // ラムダ式のBodyを取得する。MemberExpressionじゃなかったら駄目 var memberEx = propertyName.Body as MemberExpression; if (memberEx == null) throw new ArgumentException(); // () => NameのNameの部分の左側に暗黙的に存在しているオブジェクトを取得する式をゲット var senderExpression = memberEx.Expression as ConstantExpression; // ConstraintExpressionじゃないと駄目 if (senderExpression == null) throw new ArgumentException(); // ×:式を評価してsender用のインスタンスを得る // var sender = Expression.Lambda(senderExpression).Compile().DynamicInvoke(); // ○:定数なのでValueプロパティからsender用のインスタンスを得る var sender = senderExpression.Value; // 下準備が出来たので、イベント発行!! _this(sender, new PropertyChangedEventArgs(memberEx.Member.Name)); } }
これで、10000回実行して比較してみました。
実装方法 | 時間 |
---|---|
通常 | 13ms |
性能悪いイケテル方法 | 3593ms |
今回のイケテル方法 | 92ms |
結構普通の方法に迫ってきたかも。memberEx.Member.Nameでプロパティ名を取得してるところのオーバーヘッドがほとんどなんだろうなぁ。
ここは、どうしようもないのだろうか?う〜ん。