5

クラスのプロパティをインターセプトするプロキシを作成する必要があります。インターフェイスからEmitを使用して動的プロキシを作成する方法を知っていますが、インターフェイスがない場合はどうなりますか?RealProxyを使用するサンプルを見たことがあります(この例:クラスのプロパティが設定されているときにメソッドを呼び出す方法はありますか?)が、型生成と発行を使用して同じことを実現することは可能ですか?可能であれば、具象クラスの「所有者」にMarshalByRefObjectのトレースを表示させたくありません(以下を参照)。

Castleはこれを実行できると思いますが、おそらくRealProxyを隠蔽して使用しているのでしょうか。

User user = Create<User>();

public class User
{
    public string Name { get; set; } 
}

public T Create<T>()
{
    //magic happens here... :)
    return (T)GenerateInterceptingProxyFromT(typeof(T));
}
4

3 に答える 3

0

これは非常に一般的な問題であり、Miguel が提案したように AOP アプローチを選択する大きな理由であるため、INotifyPropertyChanged (プロパティ セットをインターセプトしてイベントを発生させる) の実装を示すAfterthoughtの例を作成しました

Afterthought を使用すると、プロパティのインターセプトを非常に簡単に記述できます。具体的には、プロパティの前後の値を提供することで、プロパティ セットのインターセプトを簡単にします。インターセプトするプロパティを特定するには、次のようにします。

public override void Amend<TProperty>(Property<TProperty> property)
{
    // Raise property change notifications
    if (property.PropertyInfo.CanRead && property.PropertyInfo.CanWrite)
        property.AfterSet = NotificationAmender<T>.OnPropertyChanged<TProperty>;
}

OnPropertyChangedこの場合、次のような静的メソッドを呼び出します。

public static void OnPropertyChanged<P>(INotifyPropertyChangedAmendment instance, string property, P oldValue, P value, P newValue)
{
    // Only raise property changed if the value of the property actually changed
    if ((oldValue == null ^ newValue == null) || (oldValue != null && !oldValue.Equals(newValue)))
        instance.OnPropertyChanged(new PropertyChangedEventArgs(property));
}

したがって、元のプロパティが次のようになっているとします。

string name;
public string Name 
{
    get
    {
        return name;
    }
    set
    {
        name = value;
    }
}

Afterthought を使用して上記の修正を適用すると、次のようになります。

string name;
public string Name 
{
    get
    {
        return name;
    }
    set
    {
        string oldValue = Name;
        name = value;
        NotificationAmender<ConcreteClass>.OnPropertyChanged<string>(
            this, "Name", oldValue, value, Name);
    }
}

あなたの場合、セッターの後(または前)に呼び出される静的メソッドは、好きな名前を付けて、好きなことをすることができます。これは、プロパティ セッターをインターセプトする具体的でよく知られた理由の例にすぎません。プロパティが非仮想であることがわかっている場合、インターセプトを実行するプロキシ サブクラスを作成することはできないため、Afterthought や PostSharp などの AOP アプローチが最善の策であると思います。

また、Afterthought を使用すると、結果のアセンブリが Afterthought への参照や依存関係を持たないようにインターセプトを実装できます。また、インターセプト ロジックがターゲット タイプの API を実際に追加/変更しない場合、理由はありません。具体的なクラスは結果に問題があります。

于 2011-05-23T03:33:54.163 に答える
0

.Net でのインターセプトにはいくつかのオプションがあります。

  • それがインターフェースの場合、それから動的に新しいタイプを実装し、他の内部オブジェクトを再呼び出しするプロキシを作成できます。

  • それが抽象クラスまたはオーバーライドを許可するクラスである場合、それを継承して目的のメンバーを動的にオーバーライドし、必要なことを行うことができます。

  • インターセプトする型にインターフェイス、オーバーライド可能なメソッド、またはプロパティがない場合は、読み込む前に、その型を含むアセンブリを変更する必要があります。アセンブリが読み込まれた後は、そのコードを変更することはできません。PostSharp はこのように機能すると思います。

テスト目的で使用されるモッキング ツールのほとんどは、1 番目または 2 番目の代替手段を使用しますが、オーバーライド可能なクラスのメンバー、またはインターフェイスを介して実装されたクラスのメンバーでのみ機能します。

アスペクト指向プログラミングツールは 3 番目の代替手段を使用しますが、アセンブリをロードする前にアセンブリを処理する必要があるため、より多くの作業を行う必要があります。

于 2011-05-21T17:03:19.533 に答える
0

ミゲルが言及したAOPツールの1つであるpostshrpをいじり始めたところです。あなたがやろうとしていることを機能的に行います。「静的ウィービング」を使用してコンパイル時にコードを挿入するため、消費者には見えないようにする必要があります。明らかに、これを機能させるには、インストルメント化するコードを変更する必要があります。This question
への回答は、PostSharpまたはCastleが必要なことを行わない場合のオプションである可能性のあるプロファイラーAPIの使用を提案しています。

于 2011-05-21T18:31:32.507 に答える