SSブログ

テキストボックスとInt32型のバインディング [プログラム]

M-V-VM関係の話をよく聞くのでテスト。

TextBoxふたつはっつけて,ボタンを押すと割り算の結果をTextBlockに表示するだけの簡単なプログラム。

あれ?intを直接バインドすると,"a"とかの時に,確認するすべがない……というのは困るのでさがしていると,八巻さん@グレープシティデブサミ資料を発見。 変換は,ViewModelでやるのか。なるほど。

やってると,Windows Formsアプリケーションとも共通化したくなりますが,ICommandインターフェースがWPFのものだし,いろいろ対応していないので断念。 ここらへんだけは,WinFormsでは手で書かないといけなさそうです。 でも,WinFormsでも,M-V-VMっぽいことはできそう。


C#とWordとPowerPointと [プログラム]

あいも変わらずC#でWordとPowerPointをいじくっています。

さて,要求事項にWord 2000-2007対応とかあって,その中の文字列引っ張ってくるだとか,該当する箇所の背景色かえるだとか,起動中はWord閉じるなとかの要求があるわけです。

まず,Word 2000と2002 (XP)以降で,Canvasの存在の有無という違いがあります。 また,Word 2002およびそれ以前とWord 2003および以降では,各種イベントのキャンセルがC#からできるかという違いもあります。

そこで採った方法が……ラッパライブラリ。当然,各バージョン用。バージョンによってget_ItemだったりItemだったりインデクサだったり……。 さらに,object以外に共通クラスが無いので,各バージョン用にファイルごとコピペ……。


まぁ,WordとPowerPointを弄っていると,双方の考え方の違いが分かってきます。

WordはMissing.Value,つまりはNothingを多用し,ref objectな引数たくさん。インデクサの実装とかでは結構面倒なことも多いです。 それに対して,PowerPointはrefを基本的に使いません。2値にはBooleanではなくMsoTriStateを使います。

このあたりの思想の違い,いまさら整合はとれないのでしょうが……。


PowerPointのオブジェクトは基本的にSnapshot [プログラム]

COMを使ってPowerPointを制御するプログラムを作っているのですが,TextRangeオブジェクトを弄っていると,問題発見。

ひとつのTextRangeのインスタンスからCharactersメソッドで複数の部位のTextRangeのインスタンスを作成し,真ん中あたりのTextRangeのTextプロパティに値を設定しました。 結果,そのインスタンスより後ろのインスタンスの値がずれました (StartやCountが不正になっている)。 また,場合によっては,自インスタンスの値すらずれることが……。

結局の所,PowerPointのTextRangeは取得した時点のSnapshotということみたいです。 まぁ,±2の範囲を調べて調整するようにして,自力修正をすることで対応しましたが……。


XNA GS 3.0 [プログラム]

XNA Game Studio 3.0が出たということで,インストールしてみました。

で,.NET Framewok 3.5ベースなので,LINQが使えるはず。試してみました……LINQ to Object,XBox 360実機でもOKでした。どこで使うんだ……。

XNAなのにSQL Server Compact実装して,LINQ to SQLが使えたら……笑うしかないですけどね。


コードカバレッジ気にしたらコードがひん曲がった [プログラム]

VS 2008のテストの,コードカバレッジ機能使って,未テスト箇所を作らないようにしていったのですが……。

Enum testValue = null;
foreach (Enum enumValue in Enum.GetValues(type))
{
    testValue = worker.DynamicInvoke(value, enumValue, testValue);
}

なんてコードで未テスト箇所が2箇所発生。 ちなみに,typeは任意のEnum型 (Enum型の引数valueに対して,GetType()で取得した),workerはLambdaExpression.Compileの結果。

コメントアウトしながら探すと,どうもforeach自体が問題っぽい。 foreachはIDisposableとか,色々中でやっているからなぁ,とか思いつつ,強制的に未テスト箇所を潰してやれとばかりに,できあがったコードが……。

Enum testValue = null;
foreach (Enum enumValue in (Enum.GetValues(type) as IEnumerable).OfType<Enum>())
{
    testValue = worker.DynamicInvoke(value, enumValue, testValue);
}

何かを間違えた気がしてなりません……。 というか,foreachの中で未テスト箇所作られても困るのですが……。


VS2008のテスト機能を試す [プログラム]

Visual Studio 2008のテスト機能を使ってみているのですが,なんか,普通に使う分にはNUnitとかわらないような……。 まぁ,統合されている分の優位性もあるとは思いますが,Constraint Modelが使えないのが非常に悲しい……。

統合されているとはいえ,TestDriven.NETは必須ですね。 メソッド一つの単位で,エディタ上から選択出来るのが便利です。

続きを読む


Connectにあげた [プログラム]

%入りのフォントはWPFで使えないの内容ですが,WPFとExpressionの両方にフィードバックしました。 あまりこれに引っかかる方はいないでしょうけれど,引っかかっている方 (一太郎をお使いの方など) は,是非ともVoteをお願いします。


%入りのフォントはWPFで使えない [プログラム]

一太郎などに付いてくるフォントに,"%Century Oldstyle"というものがあります。 これを,WPFでFontFamilyに指定すると,System.UriがUriFormatExceptionを起こします。

%をUri用にエスケープして,"%25Century Oldstyle"としてやると,何事もなかったように通ります。 例外スタックを見る限り,Uri使ってキャッシュしているようです。


それはそうと,Expression Blendのフォントの指定,上記の理由から全て落ちます。 原因は,ほぼ%Century Oldstyleで確定なのですが……。


UriのQueryのパース [プログラム]

ExtremeSwankとOpenIDとHttpListenerRequest書いた時は見つけていなかったので,Uriのクエリ部分のパースを自力で書いたのですが,実は,HttpUtility.ParseQueryStringという便利なメソッドがありました。 これを使えば,件のコードよりもまともな解析ができるはずです。


ORDER BYの速度 [データベース]

環境

CPU
Core 2 E6600
Physical Memory
2GB
OS
Windows XP SP3
MySQL Version
5.0.27
MySQL Table Type
InnoDB
.NET Framework Version
2.0(SP1)
ADO.NET Provider
Connector/Net 5.1.6

MySqlのバージョンが古いのは,単に昔やったプロジェクトで入っていたものを再利用しているからです。


前準備

  1. こんなテーブルを作る。
    CREATE TABLE test1 (
        ID INT PRIMARY KEY,
        Value1 INT NOT NUL UNIQUE,
        Value2 INT NOT NULL
    )
  2. test1に,ID = Value1 = Value2になるように,[1, 10000]の値を突っ込む。

計測

  • 以下のプログラムを実行する。
    using System;
    using System.Diagnostics;
    using MySql.Data.MySqlClient;
    
    class Program
    {
        static readonly string[] _commands =
        {
            "SELECT * FROM test1 ORDER BY ID",
            "SELECT * FROM test1 ORDER BY ID limit 10",
            "SELECT * FROM test1 ORDER BY Value1",
            "SELECT * FROM test1 ORDER BY Value1 limit 10",
            "SELECT * FROM test1 ORDER BY Value2",
            "SELECT * FROM test1 ORDER BY Value2 limit 10",
            "SELECT COUNT(ID) FROM test1"
        };
    
        static void Main (string[] args)
        {
            long[] ticks = new long[_commands.Length];
            Stopwatch sw = new Stopwatch();
    
            for (int i = 0; i < 10; ++i)
            {
                using (MySqlConnection conn = new MySqlConnection(
                    @"Server=localhost;Database=test;Uid=uid;Pwd=pwd"))
                {
                    conn.Open();
                    using (MySqlCommand comm = new MySqlCommand("SELECT 10", conn))
                    {
                        comm.ExecuteNonQuery();
                    }
    
                    for (int j = 0; j < _commands.Length; ++j)
                    {
                        string commandStr = _commands[j];
    
                        sw.Reset();
                        using (MySqlCommand comm = new MySqlCommand(commandStr, conn))
                        {
                            sw.Start();
                            comm.ExecuteNonQuery();
                            sw.Stop();
                        }
    
                        ticks[j] += sw.ElapsedTicks;
                    }
                    conn.Close();
                }
            }
    
            for (int j = 0; j < _commands.Length; ++j)
            {
                Console.WriteLine("{0,10}ticks : {1}", ticks[j], _commands[j]);
            }
        }
    }

さて,普通に考えたら,IDとValue1にはインデックスがあるので,ORDER BY Value1の方がORDER BY Value2よりも時間はかからなさそうです。 しかし……。

SELECT * FROM test1 ORDER BY ID
213535503ticks
SELECT * FROM test1 ORDER BY ID limit 10
5208264ticks
SELECT * FROM test1 ORDER BY Value1
465056280ticks
SELECT * FROM test1 ORDER BY Value1 limit 10
5790636ticks
SELECT * FROM test1 ORDER BY Value2
283178781ticks
SELECT * FROM test1 ORDER BY Value2 limit 10
120534615ticks
SELECT COUNT(ID) FROM test1
68597829ticks

……なんでValue2でソートした方が速くなるんだ……。念のためExplainしてみましたが,

id      select_type     table   type    possible_keys   key     key_len ref     rows    Extra
1       SIMPLE  test1   index   NULL    PRIMARY 4       NULL    10339
id      select_type     table   type    possible_keys   key     key_len ref     rows    Extra
1       SIMPLE  test1   index   NULL    PRIMARY 4       NULL    10339
id      select_type     table   type    possible_keys   key     key_len ref     rows    Extra
1       SIMPLE  test1   index   NULL    Value1  4       NULL    10339
id      select_type     table   type    possible_keys   key     key_len ref     rows    Extra
1       SIMPLE  test1   index   NULL    Value1  4       NULL    10339
id      select_type     table   type    possible_keys   key     key_len ref     rows    Extra
1       SIMPLE  test1   ALL     NULL    NULL    NULL    NULL    10339   Using filesort
id      select_type     table   type    possible_keys   key     key_len ref     rows    Extra
1       SIMPLE  test1   ALL     NULL    NULL    NULL    NULL    10339   Using filesort
id      select_type     table   type    possible_keys   key     key_len ref     rows    Extra
1       SIMPLE  test1   index   NULL    PRIMARY 4       NULL    10339   Using index

Value1はちゃんとインデックス使っている……。最新なら直っているかな?というわけで,5.0.51bを上書きでインストール。結果は……

SELECT * FROM test1 ORDER BY ID
207209592ticks
SELECT * FROM test1 ORDER BY ID limit 10
4652703ticks
SELECT * FROM test1 ORDER BY Value1
472087971ticks
SELECT * FROM test1 ORDER BY Value1 limit 10
5696766ticks
SELECT * FROM test1 ORDER BY Value2
275851026ticks
SELECT * FROM test1 ORDER BY Value2 limit 10
124287543ticks
SELECT COUNT(ID) FROM test1
67732911ticks

変わらない……。データを読ませれば変わるかと,ExecuteNonQueryの呼び出しを以下に修正。

using (MySqlDataReader reader = comm.ExecuteReader())
{
    while (reader.Read())
    {
        for (int k = 0; k < reader.FieldCount; ++k)
        {
            object o = reader[k];
        }
    }
}
SELECT * FROM test1 ORDER BY ID
497410938ticks
SELECT * FROM test1 ORDER BY ID limit 10
5393538ticks
SELECT * FROM test1 ORDER BY Value1
535218507ticks
SELECT * FROM test1 ORDER BY Value1 limit 10
6257565ticks
SELECT * FROM test1 ORDER BY Value2
622938447ticks
SELECT * FROM test1 ORDER BY Value2 limit 10
124877898ticks
SELECT COUNT(ID) FROM test1
67883031ticks

やっと逆転。でもなんかすっきりしない……。


タグ:MySQL SQL

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。