2

.NET のプロパティへの呼び出しをインターセプトしたい状況があります。私は Castle で DynamicProxy を見てきましたが、うまく動作しているようです。しかし、それを使用するには、新しいオブジェクトから始める必要があるようです。つまり、次のようなことはできません。

MyType myType = new MyType();
myType.Property = "Test";

...

MyType wrappedMyType = proxyBuilder.Wrap(myType, new MyInterceptor());
wrappedMyType.Property = "Test2";

何か足りないだけですか?

編集:

なんてこった、それはもちろん、wrappedMyType である必要があります。大ミス。ごめん。:(

4

4 に答える 4

3

そのようには機能せず、元のオブジェクトを変更することはありません。

このように考えてください。中国に引っ越して、中国の銀行の中国の銀行口座にのみ給与を支払う中国の会社で働くことを考えてみましょう。

したがって、中国の銀行口座を取得する必要があります。問題は、使用したい銀行が英語を話せないため、問題が発生することです。

これが利用可能である場合、あなたができることは、あなたに代わって銀行に電話をかけるプロキシサービス、翻訳者サービスを呼び出すことです。この代理人にあなたが言うことはすべて中国語に翻訳され、銀行の職員に言われます。彼/彼女が中国語で返答するものはすべて英語に翻訳され、あなたに話しかけられます。

事実上、銀行と話しているときに通信回線に沿って何かを行うことができるようになりました。

ただし、銀行の職員に英語を話させることはできません。

あなたの例のプロキシオブジェクトは、基になるオブジェクトを変更しません。プロキシオブジェクトでメソッドを呼び出すと、基になるオブジェクトでメソッドが呼び出され、途中で処理が行われる可能性があります。

ただし、プロキシオブジェクトを回避しても、何も変わりません。

于 2009-12-18T17:45:28.203 に答える
1

これを行うことはできません。これには正当な理由があります。これはウィンザー城に限ったことではありません。問題は、メソッドが としてマークされているという保証がないvirtualため、ラップされたオブジェクトからの状態とプロキシ オブジェクトからの状態があるという矛盾があることです。

次の非常に単純な例を考えてみてください。

abstract class AbstractPerson {
    public int Age { get; protected set; }
    public abstract void Birthday();
}

class Person : AbstractPerson {
    public Person(int age) { Age = age; }
    public override Birthday() { Age++; }
}

AbstractPersonを傍受するためのプロキシを作成したいとしましょうBirthday

class PersonProxy : AbstractPerson {
    readonly AbstractPerson wrappedPerson;

    public PersonProxy(AbstractPerson person) { 
        wrappedPerson = person;
    }
    public override void Birthday() {
        DoInterceptors();
        wrappedPerson.Birthday();
    }
    public void DoInterceptors() { 
        // do interceptors 
    }
}

Ageとしてマークされていないため、オーバーライドできないことに注意してくださいvirtual。これは、厄介な状態の不一致が発生する場所です。

Person knuth = new Person(71);
PersonProxy proxy = new PersonProxy(knuth);
Console.WriteLine(knuth.Age);
knuth.Birthday();
Console.WriteLine(knuth.Age);
Console.WriteLine(proxy.Age);

これは印刷されます

71
72
0

コンソールに。どうしたの?は仮想としてマークされていないためAge、プロキシ オブジェクトは基本動作をオーバーライドして を呼び出すことができませんwrappedPerson.Age。この例はAge = wrappedPerson.Age、コンストラクターに追加してPersonProxyも役に立たないことを示しています。私たちのプロキシは実際にはプロキシではありません。これが、既存のオブジェクトをラップできない理由です。

于 2009-12-18T18:02:01.573 に答える
0

おそらく System.Reflection.Emit.TypeBuilder を使用してこれを行うことができますが、それは簡単ではなく、おそらくすべての型で機能するとは限りません。たとえば、封印された型ではそれを行うことができませんでした。通常、型を使用する機能を維持するには、構築する型で型を継承する必要があり、基本クラスのすべてのプロパティをオーバーライドまたはシャドウする必要があるためです。 . その上、IL をオーバーライドしてイベントなどを発生させるときに、プロパティ セット メソッドの本体に IL を発行する必要があります。

これらはすべて可能ですが、簡単ではなく、完全ではありません。おそらく、別のソリューションを使用したほうがよいでしょう。私はこの種のものを楽しんでいますが、時間があれば、この回答をコードサンプルで更新します(申し訳ありませんが、「機能している」と思います)。

更新:これについて考えれば考えるほど、それは起こらないでしょう。おそらく、ラップしようとしているオブジェクトが常にインターフェイスを実装していて、それらのメンバーのみをインターセプトしたい場合。そのためのサンプルを投稿することを考えましたが、この質問を汚染すると思います. ジェイソンの回答で説明されている状況に陥る最良のシナリオ。

于 2009-12-18T17:53:58.467 に答える
0

PostSharp 、「傍受」で何をしたいのか、および元のコードを変更できるかどうかに応じて、使用できる場合があります。

これが実行可能なオプションであるためには、インターセプトする元のプロパティに属性を追加できる必要があります。(これはあなたの場合のオプションではないと推測していますが、確かなことは言えません。)これができる場合は、「ReturnValue」と呼び出しを効果的に傍受したような「FlowBehavior」。

于 2009-12-18T18:48:36.817 に答える