亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

Livetを使ってすっきりWPFアプリを作る ④サンプルプロジェクトからLivetの機能を理解する(ViewModel基本クラス編)

大分が開いてしまいましたね・・・。実は前回の縦書きSilverlightは意外としょーもないとこではまっていたり、地味に禁則処理を入れていたりで時間かけてたんですよねー。ソース込みでもうちょっとちゃんとした形で仕上げたいところです。

それはそれとして、Livetの話を今年中にい一息つきたいので再開します。でも今日はあんまり時間も無いので、軽い話題から。ViewModel基本クラスです。

ライブラリを使うにしろ自作するにしろ、このViewModel基本クラスと次回書く予定のCommandのラッピングクラス、つまりMVVMの主役となる2大インターフェース、INotifyPropertyChangedICommandをどう手っ取り早く実装するか、というのは最初にぶつかる問題なんですよね。当然、Livetにもしっかりここはサポートしています。

それでは、サンプルコード見てみましょう。INotifyPropertyChangedを実際に発行するのは、当然プロパティなんですよね。見てみましょう。

RaisePropertyChanged("Age");

・・・、はい。あんまり驚きがないんですよね、これって。一応解説しておくと、ガチで書くと以下のようになるんですよ。

if (PropertyChanged != null)
{
      PropertyChanged(new PropertyChangedEventArgs("Age"));
}

こいつを手軽に呼べるようになってるわけで、ありがたいといえばありがたいけれど、まぁ他のライブラリや自分で作るのとも大して変わりません。。。だけじゃないんですよ、Livetは( ̄ー ̄)ニヤリ

そう、よくよく見るとLivetのPropertyChangedにはオーバーロードがあります。
f:id:posaunehm:20111213233325j:image
おぉ、この書き方はあの一時期話題になった式木で頑張る書き方じゃないですかっ。okazukiさんの以下の日記にありましたよね。懐かしい!(細かい実装は違うのでしょうが)

だので、こうかけます。

RaisePropertyChanged(() => Age);

これの何が嬉しいって、やっぱりIDEのサポートがフルに受けられること。インテリセンスも出れば、リファクタリングも効く。Visual Studioという最強のIDEを使えるというC#の強みはフルに活かしていきたいのが正直なところです。ですが・・・


この書き方って、かなり遅いっていう話になった記憶があったのです。コードスニペットだと普通に文字列の方がでちゃいますし、やはり余り使うべきではないのでしょうか。

まぁ、疑問に思ったら実験ですよ。
まず、適当にViewModelを作って2つのプロパティを定義しておきます。

        #region String1変更通知プロパティ
        private string _String1;

        public string String1
        {
            get
            { return _String1; }
            set
            {
                if (EqualityComparer<string>.Default.Equals(_String1, value))
                    return;
                _String1 = value;
                RaisePropertyChanged("String1");
            }
        }
        #endregion


        #region String2変更通知プロパティ
        private string _String2;

        public string String2
        {
            get
            { return _String2; }
            set
            {
                if (EqualityComparer<string>.Default.Equals(_String2, value))
                    return;
                _String2 = value;
                RaisePropertyChanged(() => String2);
            }
        }
        #endregion

上が普通、下がイケてるほうですね。
さてさて、ではこのViewModelをコンソールでnewしてひたすら更新をかけてみましょう。コードは派手にokazukiさんのを使わせてもらってます。

        static void Main(string[] args)
        {
            var vm = new ViewModel1();
            var sw = new Stopwatch();

            sw.Restart();

            // 1万回文字列を変更
            foreach (var i in Enumerable.Range(0, 10000))
            {
                vm.String1 = "前川" + i;
            }

            Console.WriteLine("普通:\t" + sw.ElapsedMilliseconds);


            sw.Restart();
            // 1万回文字列を変更
            foreach (var i in Enumerable.Range(0, 10000))
            {
                vm.String2 = "前川" + i;
            }
            Console.WriteLine("イケてる方:\t" + sw.ElapsedMilliseconds);

            Console.Read();
            
        }

結果は。。。こんなん出ました。
f:id:posaunehm:20111213233326j:image

おお!15倍強の差。
1万回やってこの程度の差なら十分実践に耐えうるだろう、というのが個人的な感想です。そりゃあ恐ろしくプロパティ変更するところだとヤヴァイと思いますが、それはもう普通に実装しても遅いでしょう、多分。この程度ならIDEの機能と交換してもいいかな、と僕は思います。

そんな訳で今日はここまで。

#何でこんなに早いのかは実装見ておきたいな・・・。