4

C#で仮想メソッドテーブルを変更する方法はありますか?仮想メソッドが指している場所を変更するようなものですか?

class A
{
    public virtual void B()
    {
        Console.WriteLine("B");
    }
}
class Program
{
    public static void MyB(A a)
    {
        Console.WriteLine("MyB");
    }
    public static void Main(string[] Args)
    {
        A a = new A();
        // Do some reflection voodoo to change the virtual methods table here to make B point to MyB
        a.B(); // Will print MyB
    }
}
4

4 に答える 4

4

LinFuを見​​てください。

Linfuの著者のブログには、LinFu.AOP を使用して、直接制御しないクラスのメソッドの呼び出しをインターセプトして変更する例があります。

于 2011-05-01T14:32:46.420 に答える
2

リフレクションで型を変更することはできません。既存の型を反映することしかできません。

ただし、Reflection.Emit および関連するクラスを使用して新しい型を構築することはできますが、アセンブリを再コンパイルしないa.B();と、例では常にA.B().

于 2011-05-01T14:30:42.837 に答える
1

ダニ、

あなたの実際の問題は何ですか?既存のテスト済みのクラス定義を「オンザフライ」で「壊す」ことが望ましい場所の絵を描いてください。私の懐疑論を許してください...しかし、私はスクリプトの経験が豊富なので、いつでも実行されているので、それ自体が生成されないコードを使用します。私も(ある種)その理由でIOCを嫌っています。

ただし、「オンザフライ」でオーバーライド(または実装)クラス定義を作成する場合は、バイトコード生成を使用すると思います(少なくともJavaで行うことです)...ここにフォーラムがありますそのトピックに関するスレッド:http://bellyphant.com/2006/11/csharp_bytecode_generation

ソースコードを生成して、その場でコンパイルすることもできます。これは、C#をオンザフライでコンパイルするためのかわいい無料の小さなutilsクラスです:http ://www.agilekiwi.com/on_the_fly.htm

とにかく頑張ってください...それは興味深い質問です。

乾杯。キース。

于 2011-05-01T15:08:37.517 に答える
1

仮想 B コールを、選択したデフォルトのデリゲートにすることができます。以下は、継承とオーバーライドを許可します:(実際には、すでにオーバーライドされたものをオーバーライドします:D)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class A
{
    public delegate void delegateB();
    public delegateB _B;

    public A() {
      _B = B;
    }
    public void Override(delegateB newB)
    {
        _B = newB;
    }

    public virtual void B()
    {
        if (_B != null && _B != this.B) {
            Console.WriteLine("OVERRIDEN B IN A");
            _B();
        }
        else {
        Console.WriteLine("VIRTUAL B IN A");
        }
    }
}

    class cB : A {
        public override void B() {
            if (base._B != null && base._B != this.B)
            {
                Console.WriteLine("OVERRIDEN B IN B");
                _B();
            }
            else
            {
                Console.WriteLine("IN B");
            }

        }
    }

class Program
{
    class Overrider {
       public void MyB()
       {
           Console.WriteLine("MyB");
       }
    }

    public static void Main(string[] Args)
    {
        A a = new A();
        a.B();
        Overrider ovr = new Overrider();
        a.Override(ovr.MyB);
        a.B(); // Will print MyB
        cB b = new cB();
        b.B();
        b.Override(ovr.MyB);
        b.B();
    }
}
}

出力:

VIRTUAL B IN A
OVERRIDEN B IN A
MyB
IN B
OVERRIDEN B IN B
MyB

オーバーライドされたデリゲートを効果的に呼び出す cB.B() を呼び出すこともできbase.B();ますが、次の出力が得られます。

VIRTUAL B IN A
OVERRIDEN B IN A
MyB
IN B
OVERRIDEN B IN B
OVERRIDEN B IN A
MyB

類似のアプローチまたはデザイン パターン アプローチを採用することをお勧めします。コードは高性能アプリケーションでは使用できなくなります。デリゲートは速く、リフレクションは遅いです。

于 2011-05-01T14:51:53.690 に答える