プロキシクラスを動的に作成しようとしています。これを行うための非常に優れたフレームワークがあることは知っていますが、これは純粋に学習プロジェクトとしてのペットプロジェクトなので、自分でやりたいと思います。
たとえば、インターフェイスを実装する次のクラスがある場合:
interface IMyInterface
{
void MyProcedure();
}
class MyClass : IMyInterface
{
void MyProcedure()
{
Console.WriteLine("Hello World");
}
}
それらをログに記録するためにこのクラスのメソッドをインターセプトするために、同じインターフェースを実装しているが「実際の」クラスへの参照を含む別のクラス(プロキシクラスの私のバージョン)を作成しています。このクラスはアクション(ロギングなど)を実行してから、実際のクラスで同じメソッドを呼び出します。
例えば:
class ProxyClass : IMyInterface
{
private IMyInterface RealClass { get; set; }
void MyProcedure()
{
// Log the call
Console.WriteLine("Logging..");
// Call the 'real' method
RealClass.MyProcedure();
}
}
次に、呼び出し元は代わりにプロキシクラスのすべてのメソッドを呼び出します(実際のクラスの代わりに基本的な自家製のIoCコンテナを使用してプロキシクラスを注入しています)。実行時にRealClass
を同じインターフェイスを実装する別のクラスにスワップアウトできるようにするため、このメソッドを使用しています。
実行時にProxyClass
を作成し、そのRealClass
プロパティを設定して、実際のクラスのプロキシとして使用できるようにする方法はありますか?これを行う簡単な方法はありますか、Reflection.Emit
およびMSILを生成しますか?
System.Runtime.Remoting.Proxies.RealProxy をご覧ください。これを使用して、呼び出し元の観点からはターゲットタイプのように見えるインスタンスを作成できます。 RealProxy.Invokeは、基になる型でターゲットメソッドを呼び出すか、呼び出しの前後に追加の処理(ログ記録など)を実行できるポイントを提供します。
各メソッド呼び出しの前後にコンソールにログを記録するプロキシの例を次に示します。
public class LoggingProxy<T> : RealProxy
{
private readonly T _instance;
private LoggingProxy(T instance)
: base(typeof(T))
{
_instance = instance;
}
public static T Create(T instance)
{
return (T)new LoggingProxy<T>(instance).GetTransparentProxy();
}
public override iMessage Invoke(iMessage msg)
{
var methodCall = (IMethodCallMessage)msg;
var method = (MethodInfo)methodCall.MethodBase;
try
{
Console.WriteLine("Before invoke: " + method.Name);
var result = method.Invoke(_instance, methodCall.InArgs);
Console.WriteLine("After invoke: " + method.Name);
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e);
if (e is TargetInvocationException && e.InnerException != null)
{
return new ReturnMessage(e.InnerException, msg as IMethodCallMessage);
}
return new ReturnMessage(e, msg as IMethodCallMessage);
}
}
}
使用方法は次のとおりです。
IMyInterface intf = LoggingProxy<IMyInterface>.Create(new MyClass());
intf.MyProcedure();
コンソールへの出力は次のようになります。
呼び出す前:MyProcedure
こんにちは世界
呼び出し後:MyProcedure
たぶん私は質問を誤解しているかもしれません、コンストラクタはどうですか?
class ProxyClass : IMyInterface
{
public ProxyClass(IMyInterface someInterface)
{
RealClass = someInterface;
}
// Your other code...
}