动态创建代理类

Dav*_*e S 36 .net c# reflection proxy

我正在尝试动态创建代理类.我知道有一些非常好的框架可以做到这一点,但这纯粹是一个宠物项目作为一个学习练习,所以我想自己做.

例如,如果我有以下类实现接口:

interface IMyInterface
{
    void MyProcedure();
}

class MyClass : IMyInterface
{
    void MyProcedure()
    {
        Console.WriteLine("Hello World");
    }
}
Run Code Online (Sandbox Code Playgroud)

为了拦截这个类的方法以便记录它们,我正在创建另一个类(我的代理类版本),它实现相同的接口但包含对"真实"类的引用.此类执行操作(例如,日志记录),然后在真实类上调用相同的方法.

例如:

class ProxyClass : IMyInterface
{
    private IMyInterface RealClass { get; set; }

    void MyProcedure()
    {
        // Log the call
        Console.WriteLine("Logging..");

        // Call the 'real' method
        RealClass.MyProcedure();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后调用者调用代理类上的所有方法(我使用基本的home-brew IoC容器来注入代理类来代替真正的类).我正在使用此方法,因为我希望能够RealClass在运行时将其换出到另一个实现相同接口的类.

有没有办法ProxyClass在运行时创建并填充其RealClass属性,以便它可以用作真实类的代理?是否有一种简单的方法可以做到这一点,还是需要使用类似的东西Reflection.Emit并生成MSIL?

bra*_*dmo 51

看看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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是如何使用它:

IMyInterface intf = LoggingProxy<IMyInterface>.Create(new MyClass());
intf.MyProcedure();
Run Code Online (Sandbox Code Playgroud)

然后输出到控制台将是:

在调用之前:MyProcedure
Hello World
调用之后:MyProcedure

  • 但是,一个重要的限制是包装到代理中的类型应该来自MarshalByRefObject. (24认同)
  • 这就是我一直在寻找的东西,并为我指明了正确的方向。谢谢。 (2认同)
  • @Piedone,要包装的类型应该是接口或派生自 MarshalByRefObject (2认同)