2009-04-17 13 views
6

私がしようとしているのは、C#クラス内のいずれかのプロパティが設定されているとき(逆に、取得時にはpropertyWasGot())、単一のpropertyWasSet()関数を呼び出すことです。私はまた、どのプロパティの 'get'が呼び出されたのか知りたいです。クラスのプロパティが設定されているときにメソッドを呼び出す方法はありますか?

私は、 '設定'されているプロパティの二項関係を維持し、まだ設定されていれば「取得」アクションをチェックします(そうでなければエラーを投げます)。

私は反射、代表者などのためにmsdnのドキュメントを見てきましたが、これが可能であるかどうかは完全にはわかりません。

これを行う方法はありますか?基本クラスなどで傍受されるこれらの関数の1つを呼び出したときにイベントを発生させますか?

答えて

0

私はあなたが必要と考えるものは、WPF依存性プロパティシステムに非常に似ています。その実装を見たいかもしれません。とにかく、各プロパティのgetterとsetterにインターセプトコードを追加することもできます。

+0

ええ、私はいくつかあるので、すべてのプロパティにチェックを追加するのを避けようとしています、そして、コードはそれぞれほぼ同じです。 –

3

この種のタスクについては、PostSharpを調べるとよいでしょう。これは、C#(またはそれに関する任意の.NET言語)上で動作するように設計されており、リフレクションでコードを乱雑にしないという利点もあります。実際には、それぞれのプロパティに手動でコードを追加しなくても、C#/ Reflectionを純粋に使用するソリューションを見つけることはできないと思いますので、PostSharpを使用することをお勧めします。

0

自分で作成しない場合は、このようなことはありません。

+0

私は実行時に新しいクラスを作成し、すべてのクラスプロパティをラップするメソッドにラップしてから通常のビジネスに移りましたが、これも可能かどうかは分かりません。 –

7

Getのために簡単に拡張できるSetのインターセプタをもう一週間書きました。RealProxyを使用しています。つまり、基本クラスがMarshalByRefObjectを派生させる必要があります。

また、クラスを抽象化し、Reflection Emitを使用して、すべてのプロパティをラップする具体的なクラスを構築することもできます。

また、あなたはこのまたはPostSharpを回避するために、コードジェネレータで見ることができる...このソリューションの

パフォーマンスが恒星ではありませんが、それが結合最もUIのために十分高速である必要があります。これは、プロキシ呼び出しのためのLCGメソッドを生成することによって改善することができます。

public interface IInterceptorNotifiable { 
    void OnPropertyChanged(string propertyName); 
} 

/// <summary> 
/// A simple RealProxy based property interceptor 
/// Will call OnPropertyChanged whenever and property on the child object is changed 
/// </summary> 
public class Interceptor<T> where T : MarshalByRefObject, IInterceptorNotifiable, new() { 

    class InterceptorProxy : RealProxy { 
     T proxy; 
     T target; 
     EventHandler<PropertyChangedEventArgs> OnPropertyChanged; 

     public InterceptorProxy(T target) 
      : base(typeof(T)) { 
      this.target = target; 
     } 

     public override object GetTransparentProxy() { 
      proxy = (T)base.GetTransparentProxy(); 
      return proxy; 
     } 


     public override IMessage Invoke(IMessage msg) { 

      IMethodCallMessage call = msg as IMethodCallMessage; 
      if (call != null) { 

       var result = InvokeMethod(call); 
       if (call.MethodName.StartsWith("set_")) { 
        string propName = call.MethodName.Substring(4); 
        target.OnPropertyChanged(propName); 
       } 
       return result; 
      } else { 
       throw new NotSupportedException(); 
      } 
     } 

     IMethodReturnMessage InvokeMethod(IMethodCallMessage callMsg) { 
      return RemotingServices.ExecuteMessage(target, callMsg); 
     } 

    } 

    public static T Create() { 
     var interceptor = new InterceptorProxy(new T()); 
     return (T)interceptor.GetTransparentProxy(); 
    } 


    private Interceptor() { 
    } 

} 

使用法:あなたの要求の

class Foo : MarshalByRefObject, IInterceptorNotifiable { 
     public int PublicProp { get; set; } 
     public string lastPropertyChanged; 

     public void OnPropertyChanged(string propertyName) { 
      lastPropertyChanged = propertyName; 
     } 

    } 


    [Test] 
    public void TestPropertyInterception() { 

     var foo = Interceptor<Foo>.Create(); 
     foo.PublicProp = 100; 

     Assert.AreEqual("PublicProp", foo.lastPropertyChanged); 

    } 
} 
+0

これは本当に面白いです。私は、オブジェクトのコンストラクタ内にCreate()を実行できると仮定しています。したがって、すべてのオブジェクトのインスタンス化を明示的に変更する必要はありません。 私はこれと一緒に遊ぶつもりです。本当にありがとう! –

+0

私はあなたが本当にあなたのオブジェクトのためのファクトリを必要としていると思います。それは、とにかく(あなたが後でオブジェクトの実装を交換し、オブジェクトインスタンスをキャッシュすることを可能にするので) –

0

SET部分はWPF依存関係プロパティシステムに非常によく似ています。 しかし、GET部分は、WPF依存関係プロパティーシステムでさえも抜けているような珍しいものです!

関連する問題