オブジェクトに特定の機能を追加するために、動的なプロキシオブジェクトを作成します。
基本的には、オブジェクトを受け取り、取得した元のオブジェクトと同一のオブジェクトでラップし、すべての呼び出しをインターセプトします。
class Wrapper : DynamicProxy// dynamic proxy is not a reall class, but i guess something like this exists...
{
public static T Wrap(T obj)
{
return (T) new Wrapper(obj);
}
public override object InterceptCall(MethodInfo info, object[] args)
{
// do stuff
}
}
明確にするために、WCFチャネルファクトリに似た何かをしたい...
クラス(プロキシではない)をプロキシし、非仮想メソッドを処理する(「new」キーワードでmethondを継承して追加したかのように)良い方法が必要なので、賞金を追加します。 .Netが行うように、これらはすべて非常に可能性が高いと確信しています。
私はこれをもっと早く書くべきでしたが、気にしません。
私の問題には、インターフェイスではなくクラスをプロキシするために必要な特別な「落とし穴」がありました。
これには2つの解決策があります。
Real Proxy and friends、基本的には.Net Remotingを使用することを意味します。 ContextBoundObjectから継承する必要があります。
System.Reflection.Emit を使用してプロキシを構築する spring と同様に、 ProxyFactoryObject のコードも参照できます。 別の 3 記事subject にあります。
ところで、2番目のアプローチにはかなりの制限があり、非仮想メソッドをプロキシすることはできません。
DynamicObject と ImpromptuInterface の組み合わせでこれを行うことができますが、プロキシする機能とプロパティを実装するインターフェイスが必要です。
public interface IDoStuff
{
void Foo();
}
public class Wrapper<T> : DynamicObject
{
private readonly T _wrappedObject;
public static T1 Wrap<T1>(T obj) where T1 : class
{
if (!typeof(T1).IsInterface)
throw new ArgumentException("T1 must be an Interface");
return new Wrapper<T>(obj).ActLike<T1>();
}
//you can make the contructor private so you are forced to use the Wrap method.
private Wrapper(T obj)
{
_wrappedObject = obj;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
try
{
//do stuff here
//call _wrappedObject object
result = _wrappedObject.GetType().GetMethod(binder.Name).Invoke(_wrappedObject, args);
return true;
}
catch
{
result = null;
return false;
}
}
}
もちろん、タイプセーフを失い、私が示したようにDynamicObjectを使用して、ダックキャスティングを削除することもできます。
このオブジェクトプロキシの透明な拡張可能なバージョンを作成し、それをオープンソース化しました here 。
Castle.DynamicProxy に加えて、 LinFu.DynamicProxy on Github もあります。
PostSharp を見てください。 Vanilla .Netであなたが望むことをする方法はわかりませんが、PostSharpは、メソッド内でコードを置換またはラップするために使用できる "OnMethodBoundaryAspect"などを提供します。
ロギング、パラメーター検証、例外処理などの処理に使用しました。
無料のCommunity Editionがあります。開発マシンと、使用するビルドサーバーにインストールする必要があります。
別のオプションは ContextBoundObject
です。
8〜9年前に、このアプローチを使用してメソッド呼び出しをトレースするCodeProjectに関する記事がありました。
クラス内のすべての関数の前後に機能を追加するには、リアルプロキシが適切なアプローチです。
そのため、Tには任意のTestClassを使用できます。 TestClass-に対してこのようなインスタンスを作成します
var _instance =(object)DynamicProxy(TestClass).GetTransparentProxy();
ダイナミックプロキシのコード
class DynamicProxy<T> : RealProxy
{
readonly T decorated;
public DynamicProxy(T decorated) : base(typeof(T))
{
this.decorated = decorated;
}
public override iMessage Invoke(iMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as MethodInfo;
string fullMethodName = $"{methodInfo.DeclaringType.Name}.{methodCall.MethodName}";
try
{
var result = methodInfo.Invoke(decorated, methodCall.InArgs);
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (Exception e)
{
return new ReturnMessage(e, methodCall);
}
finally
{
}
}
}