动态创建一个代理类(Dynamically creating a proxy class)

2019-08-18 10:18发布

我想动态创建一个代理类。 我知道有一些很不错的框架存在,要做到这一点,但是这纯粹是作为一个学习锻炼,想自己做一个宠物项目。

如果,例如,我有下面的类实现一个接口:

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?

Answer 1:

看一看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



Answer 2:

您可以使用动态对象所描述的这个问题 ,但对于一个动态生成的,强类型的对象,你必须使用Reflection.Emit ,因为你嫌。 此博客已呈现出类型的动态创建和实例化的示例代码。

我已阅读, 罗斯林具有的功能,这使得动态代理更容易创造,所以也许看看那里。



Answer 3:

也许我误解了这个问题,如何构造?

class ProxyClass : IMyInterface
{
    public ProxyClass(IMyInterface someInterface)
    {
        RealClass = someInterface;
    }
   // Your other code...
}


Answer 4:

我不建议这样做。 通常你用一些知名库,如城堡或EntLib。 对于一些复杂的类可能是相当动态生成的代理是一个挑战。 下面是这样做,使用“是”多态的一个例子。 对于这一点,你必须在基地为虚拟所有的方法声明。 你试图做的方式(“有”)也是可以的,但对我来说看起来更为复杂。

public class A
{
    public virtual void B()
    {
        Console.WriteLine("Original method was called.");
    }
}

class Program
{

    static void Main(string[] args)
    {
        // Create simple assembly to hold our proxy
        AssemblyName assemblyName = new AssemblyName();
        assemblyName.Name = "DynamicORMapper";
        AppDomain thisDomain = Thread.GetDomain();
        var asmBuilder = thisDomain.DefineDynamicAssembly(assemblyName,
                     AssemblyBuilderAccess.Run);

        var modBuilder = asmBuilder.DefineDynamicModule(
                     asmBuilder.GetName().Name, false);

        // Create a proxy type
        TypeBuilder typeBuilder = modBuilder.DefineType("ProxyA",
           TypeAttributes.Public |
           TypeAttributes.Class |
           TypeAttributes.AutoClass |
           TypeAttributes.AnsiClass |
           TypeAttributes.BeforeFieldInit |
           TypeAttributes.AutoLayout,
           typeof(A));
        MethodBuilder methodBuilder = typeBuilder.DefineMethod("B", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot);
        typeBuilder.DefineMethodOverride(methodBuilder, typeof(A).GetMethod("B"));


        // Generate a Console.Writeline() and base.B() calls.
        ILGenerator ilGenerator = methodBuilder.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.EmitWriteLine("We caught an invoke! B method was called.");

        ilGenerator.EmitCall(OpCodes.Call, typeBuilder.BaseType.GetMethod("B"), new Type[0]);
        ilGenerator.Emit(OpCodes.Ret);

        //Create a type and casting it to A. 
        Type type = typeBuilder.CreateType();
        A a = (A) Activator.CreateInstance(type);

        // Test it
        a.B();
        Console.ReadLine();
    }
}


文章来源: Dynamically creating a proxy class