3

在调用 RealProxy 基本构造函数时,您传递要代理的目标对象的类型。我想做的是动态地将接口​​添加到代理类型,以便可以将生成的代理类型强制转换为其他接口。

例如:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace ConsoleApplication17
{
    class Program
    {
        static void Main(string[] args)
        {
            MyProxy<IFoo> proxy = new MyProxy<IFoo>(new Foo());

            IFoo proxiedFoo = (IFoo)proxy.GetTransparentProxy();

            // make a proxied call...
            proxiedFoo.DoSomething();

            // cast proxiedFoo to IDisposable and dispose of it...
            IDisposable disposableFoo = proxiedFoo as IDisposable;

            // disposableFoo is null at this point.

            disposableFoo.Dispose();
        }
    }
}

public interface IFoo
{
    void DoSomething();
}

public class Foo : IFoo, IDisposable
{
    #region IFoo Members

    public void DoSomething()
    {
        //
    }

    #endregion

    #region IDisposable Members

    public void Dispose()
    {
        // dispose
    }

    #endregion
}

public class MyProxy<T> : RealProxy where T : class
{
    private T _target;

    public MyProxy(T target) :
        base(CombineType(typeof(T), typeof(IDisposable)))
    {
        this._target = target;
    }

    private static Type CombineType(Type type1, Type type2)
    {
        // How to implement this method, Reflection.Emit????
        throw new NotImplementedException();
    }

    public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
    {
        return InvokeRemoteCall((IMethodCallMessage)msg, this._target);
    }

    /// <summary>
    /// Invokes the remote call.
    /// </summary>
    /// <param name="methodCall">The method call.</param>
    /// <param name="target">The target.</param>
    /// <returns>A <see cref="ReturnMessage"/></returns>
    private static IMessage InvokeRemoteCall(IMethodCallMessage methodCall, object target)
    {
        MethodInfo method = methodCall.MethodBase as MethodInfo;

        object callResult = (target != null) ? method.Invoke(target, methodCall.InArgs) : null;

        LogicalCallContext context = methodCall.LogicalCallContext;

        var query = method.GetParameters().Where(param => ((ParameterInfo)param).IsOut);

        ParameterInfo[] outParameters = query.ToArray();

        return new ReturnMessage(callResult, outParameters, outParameters.Count(), context, methodCall);
    }
}
}

因此,为了能够将代理类型转换为,除了基本构造函数调用之外IDisposable,我还需要能够发送。IDisposableIFooRealProxy

本质上,我如何实现这个方法来动态添加IDisposableIFoo被代理。

private static Type CombineType(Type type1, Type type2)
{
    // How to implement this method, Reflection.Emit????
    throw new NotImplementedException();
}
4

2 回答 2

9

有一种非常简单的内置方法可以实现这一目标。但是,如果一个人还不知道它实际上是无法发现的:-)

为了能够控制在从某个RealProxy派生类获得的透明代理相关联的透明代理上哪些强制转换操作是有效的,RealProxy需要实现一个附加接口,即IRemotingTypeInfo.

IRemotingTypeInfo接口定义的方法之一是bool CanCastTo(Type type, object o). 每次尝试将代理对象转换为其他类型时都会调用此方法;转换操作的“目标”类型可通过type参数访问。

因此,要允许您的代理“实现”多个接口,只需从您希望支持的类型true的方法返回。CanCastTo()

请注意,在转换之后,透明代理上的方法调用仍由同一RealProxy实例接收。

如需更深入的讨论,您可以阅读此 MSDN 文章:使用 .NET Remoting 和 COM 互操作创建自定义编组实现

这是一个完整的例子:

interface IFaceA
{
    void MethodA();
}

interface IFaceB
{
    void MethodB();
}

class MultiFaceProxy : RealProxy, IRemotingTypeInfo
{
    public MultiFaceProxy()
        :base(typeof(IFaceA)) {}

    public bool CanCastTo(Type fromType, object o)
    {
        return fromType == typeof(IFaceA) || fromType == typeof(IFaceB);
    }

    public string TypeName
    {
        get { return GetProxiedType().FullName; }
        set { throw new NotSupportedException(); }
    }

    public override IMessage Invoke(IMessage msg)
    {
        // invoke logic
        return null;
    }
}

class Program
{
    static void Main(string[] args)
    {
        MultiFaceProxy proxy = new MultiFaceProxy();

        IFaceA ifa = (IFaceA) proxy.GetTransparentProxy();
        // The following now also works thanks to CanCastTo()
        IFaceB ifb = (IFaceB)ifa;
     }
}
于 2015-02-18T14:13:56.243 回答
1

我解决了。这是使用反射发射的完整解决方案。

using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace ConsoleApplication17
{
    class Program
    {
        static void Main(string[] args)
        {
            MyProxy<IFoo> proxy = new MyProxy<IFoo>(new Foo());

            IFoo proxiedFoo = (IFoo)proxy.GetTransparentProxy();

            // make a proxied call...
            proxiedFoo.DoSomething();

            // cast proxiedFoo to IDisposable and dispose of it...
            IDisposable disposableFoo = proxiedFoo as IDisposable;

            // disposableFoo is null at this point.

            disposableFoo.Dispose();
        }
    }

    public interface IFoo
    {
        void DoSomething();
    }

    public class Foo : IFoo, IDisposable
    {
        #region IFoo Members

        public void DoSomething()
        {
            Console.WriteLine("DoSomething called!");
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            // dispose
            Console.WriteLine("Disposing Foo!");
        }

        #endregion
    }

    public class MyProxy<T> : RealProxy where T : class
    {
        private T _target;

        public MyProxy(T target) :
            base(CombineType(typeof(T), typeof(IDisposable)))
        {
            this._target = target;
        }

        private static Type CombineType(Type type1, Type type2)
        {
            // How to implement this method, Reflection.Emit????
            return DynamicInterfaceFactory.GenerateCombinedInterfaceType(type1, type2);
        }

        public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
        {
            return InvokeRemoteCall((IMethodCallMessage)msg, this._target);
        }

        /// <summary>
        /// Invokes the remote call.
        /// </summary>
        /// <param name="methodCall">The method call.</param>
        /// <param name="target">The target.</param>
        /// <returns>A <see cref="ReturnMessage"/></returns>
        private static IMessage InvokeRemoteCall(IMethodCallMessage methodCall, object target)
        {
            MethodInfo method = methodCall.MethodBase as MethodInfo;

            object callResult = (target != null) ? method.Invoke(target, methodCall.InArgs) : null;

            LogicalCallContext context = methodCall.LogicalCallContext;

            var query = method.GetParameters().Where(param => ((ParameterInfo)param).IsOut);

            ParameterInfo[] outParameters = query.ToArray();

            return new ReturnMessage(callResult, outParameters, outParameters.Count(), context, methodCall);
        }
    }

    public static class DynamicInterfaceFactory
    {
        public static Type GenerateCombinedInterfaceType(Type type1, Type type2)
        {            
            if (!type1.IsInterface)
                throw new ArgumentException("Type type1 is not an interface", "type1");

            if (!type2.IsInterface)
                throw new ArgumentException("Type type2 is not an interface", "type2");

            //////////////////////////////////////////////
            // Module and Assembly Creation

            var orginalAssemblyName = type1.Assembly.GetName().Name;

            ModuleBuilder moduleBuilder;

            var tempAssemblyName = new AssemblyName(Guid.NewGuid().ToString());

            var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
                tempAssemblyName,
                System.Reflection.Emit.AssemblyBuilderAccess.RunAndCollect);

            moduleBuilder = dynamicAssembly.DefineDynamicModule(
                tempAssemblyName.Name,
                tempAssemblyName + ".dll");


            var assemblyName = moduleBuilder.Assembly.GetName();

            //////////////////////////////////////////////

            //////////////////////////////////////////////
            // Create the TypeBuilder

            var typeBuilder = moduleBuilder.DefineType(
                type1.FullName,
                TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);

            typeBuilder.AddInterfaceImplementation(type1);
            typeBuilder.AddInterfaceImplementation(type2);

            //////////////////////////////////////////////

            //////////////////////////////////////////////
            // Create and return the defined type

            Type newType = typeBuilder.CreateType();

            return newType;

            //////////////////////////////////////////////
        }
    }
}

关键是创建一个新的接口类型,它是传入的两个接口的组合。然后 RealProxy 可以将新的动态接口方法映射到我们的 MyProxy Invoke 方法,然后我们可以调用适当的方法。

现在看一下对 CombineType 的调用:

private static Type CombineType(Type type1, Type type2)
{
    // How to implement this method, Reflection.Emit????
    return DynamicInterfaceFactory.GenerateCombinedInterfaceType(type1, type2);
}

然后创建一个简单的内存组合接口。

public static class DynamicInterfaceFactory
{
    public static Type GenerateCombinedInterfaceType(Type type1, Type type2)
    {            
        if (!type1.IsInterface)
            throw new ArgumentException("Type type1 is not an interface", "type1");

        if (!type2.IsInterface)
            throw new ArgumentException("Type type2 is not an interface", "type2");

        //////////////////////////////////////////////
        // Module and Assembly Creation

        var orginalAssemblyName = type1.Assembly.GetName().Name;

        ModuleBuilder moduleBuilder;

        var tempAssemblyName = new AssemblyName(Guid.NewGuid().ToString());

        var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
            tempAssemblyName,
            System.Reflection.Emit.AssemblyBuilderAccess.RunAndCollect);

        moduleBuilder = dynamicAssembly.DefineDynamicModule(
            tempAssemblyName.Name,
            tempAssemblyName + ".dll");


        var assemblyName = moduleBuilder.Assembly.GetName();

        //////////////////////////////////////////////

        //////////////////////////////////////////////
        // Create the TypeBuilder

        var typeBuilder = moduleBuilder.DefineType(
            type1.FullName,
            TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);

        typeBuilder.AddInterfaceImplementation(type1);
        typeBuilder.AddInterfaceImplementation(type2);

        //////////////////////////////////////////////

        //////////////////////////////////////////////
        // Create and return the defined type

        Type newType = typeBuilder.CreateType();

        return newType;

        //////////////////////////////////////////////
    }
}

哪个被传递给 RealProxy c'tor

public class MyProxy<T> : RealProxy where T : class
{
    private T _target;

    public MyProxy(T target) :
        base(CombineType(typeof(T), typeof(IDisposable)))
    {
        this._target = target;
    }

程序输出:

DoSomething called!
Disposing Foo!
Press any key to continue . . .

这还不是万无一失的,但它是一个入门者。

于 2013-08-20T21:19:55.257 回答