VB2005のMyClass.Method

某所より。

ところで、VB2005にある
MyClass.Hoge( );
というvirtual指定がされていても強制的に自分自身の
クラスのメソッドを呼び出す記法は、C#にはなかとですか?(´ω`)

それ以前に、VBが分かっていないので、VBのコードを理解するところからスタート。(^^;

Public Class Foo
    Public Overridable Function Method(x as Integer, y as Integer) as Integer
        Return x + y
    End Function

    Public Sub Test()
        Console.WriteLine (MyClass.Method(10, 20))
        Console.WriteLine (Method(10, 20))
    End Sub
End Class

Public Class Bar
    Inherits Foo

    Public Overrides Function Method(x as Integer, y as Integer) as Integer
        Return x * y
    End Function

End Class

Module App
    Sub Main()
        Dim bar as New Bar
        bar.Test ()
    End Sub
End Module 

' 結果
' 30
' 200

このように仮想関数であっても、自分のクラスで定義されている実装を呼び出す機能のようです。では、具体的にどんなことが起きているのか、ILを覗いてみましょう。

.method public instance void  Test() cil managed
{
  // コード サイズ       31 (0x1f)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.s   10
  IL_0003:  ldc.i4.s   20
  IL_0005:  call       instance int32 Foo::Method(int32,
                                                  int32)
  IL_000a:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_000f:  ldarg.0
  IL_0010:  ldc.i4.s   10
  IL_0012:  ldc.i4.s   20
  IL_0014:  callvirt   instance int32 Foo::Method(int32,
                                                  int32)
  IL_0019:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_001e:  ret
} // end of method Foo::Test

callで呼び出しているか、callvirtで呼び出しているかの違いだけのようですね。自分の知る限りだとC#ではサポートしていないと思います。個人的には仮想関数を無効にするような機能は混乱の元なので無くても良い気がします。

ただ、「C#で出来ない」というのは気に入らない(笑)ので無理矢理書いてみました。

using System;
using System.Reflection;
using System.Reflection.Emit;

delegate R MethodDelegate<T,R>(object instance, T arg1, T arg2);

public static class MethodCreator {
    static int n = 0;
    public static DynamicMethod Binary<T,R>(MethodInfo mi) {
        DynamicMethod dm = new DynamicMethod("tempMethod" + n++,
                typeof(R), new Type[] {typeof(object), typeof(T), typeof(T)}, 
                mi.DeclaringType);
        ILGenerator il = dm.GetILGenerator();

        if (mi.IsStatic)
            throw new ArgumentException();

        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Ldarg_2);
        il.Emit(OpCodes.Call, mi);
        il.Emit(OpCodes.Ret);

        return dm;
    }
}

public class Foo {
    static MethodDelegate<int,int> MyClassMethod;

    static Foo() {
        MethodInfo mi = typeof(Foo).GetMethod("Method");
        DynamicMethod dm = MethodCreator.Binary<int,int>(mi);
        MyClassMethod = (MethodDelegate<int,int>)dm.CreateDelegate(
                typeof(MethodDelegate<int,int>));
    }

    public virtual int Method(int x, int y) {
        return x + y;
    }

    public void Test() {
        // Foo.Methodを呼び出す
        Console.WriteLine (MyClassMethod(this, 10, 20));
        Console.WriteLine (Method(10, 20));
    }
}

public class Bar : Foo {
    public override int Method(int x, int y) {
        return x * y;
    }
}

public static class App {
    public static void Main() {
        new Bar().Test();
    }
}

/* 結果
30
200
 */

・・・いや、これはC#じゃないだろ・・・(^^;