FastPropertyComparer その3

もうかれこれ一週間もこれいじってるのか!間口が広いライブラリを作るのは大変ですねぇ。
で、新しいバグを2件見つけました。再現コード。

using System;
using System.Collections.Generic;
using SioKoshou;

interface IDetarame { char Value { get; } }

struct S1 : IDetarame
{
  private char val;
  public char Value { get { return val; } }

  public S1( char c ) { this.val = c; }
}

struct S2
{
  private char val;
  public char Value { get { return val; } }

  public S2( char c ) { this.val = c; }
}

class Program
{
  static void Main()
  {
    S1 a1 = new S1( 'a' ), b1 = new S1( 'b' );
    S2 a2 = new S2( 'a' ), b2 = new S2( 'b' );

    Console.WriteLine( "S1: CompareTo: " + a1.Value.CompareTo( b1.Value )
      + ", fast: " + FastPropertyComparer.Factory<S1>( "Value" )( a1, b1 ) );

    Console.WriteLine( "S2: CompareTo: " + a2.Value.CompareTo( b2.Value )
      + ", fast: " + FastPropertyComparer.Factory<S2>( "Value" )( a2, b2 ) );

    Console.WriteLine( "IDetarame: CompareTo: " + a1.Value.CompareTo( b1.Value )
      + ", fast: " + FastPropertyComparer.Factory<IDetarame>( "Value" )(
        ( IDetarame ) a1, ( IDetarame ) b1 ) ); // box化

    Console.ReadKey();
  }
}

struct S1とS2の違いは、IDetarameを継承しているかどうかの違いだけ。
結果は

S1: CompareTo: -1, FastPropertyComparer.Compare: -1
S2: CompareTo: -1, FastPropertyComparer.Compare: 0

3つ目の比較はArgumentException。「DynamicMethod に対する型オーナーが無効です。」だそうで。そうでした、インターフェイスを忘れてましたorz
id:siokoshou:20070510の謎の例外には対応したけど、まだDynamicMethodの使い方が間違ってました。インターフェイスにメソッドは作れません。なので、正しいコードはこう。

t = typeof( T );
DynamicMethod dm = new DynamicMethod(
  "Compare", typeof( int ), new Type[] { t, t }, t.Module, true );

動的メソッドを型に関連付けて作るのではなく、モジュールに関連付けて作れば、インターフェイスに対しても正しく動きました。なんでモジュールに関連付けて作る必要があるんだ?と思ってたけど、なるほど納得。むしろ、型に関連付けて作る必要があるのか?わからなくなってしまいました。
ちなみに、値型をインターフェイス型にキャストして使うのは激しく非推奨です。ボックス化の遅さをなめちゃいけません。ボックス化した方の値を変更して、元の値が変更されてないって悲劇もありがちです。

もう一件のバグは、2つ目の比較が正しくできないこと。一つ目はきちんとできてるのになんでだろ?わかりません(^^;
動的メソッドのデバッグってどうやるんだ…。あ、printfデバッグか。ILGenerator.EmitWriteLineっていう、ツンなILGeneratorにしてはデレなメソッドがあるのはデバッグに使えってことだったのかw いや、これでデレと感じるのは麻痺してるかもww