How to dynamically combine two interfaces to pass to RealProxy

Jim

In a call to the RealProxy base constructor, you pass the Type of the target object to be proxied. What I would like to do is dynamically add interfaces to the proxied type so that the resultant proxied type can be cast to the additional interfaces.

For example:

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);
    }
}
}

So in order to be able cast the proxied type to IDisposable, I need to be able to send IDisposable in addition to IFoo to the RealProxy base constructor call.

In essence, how do I implement this method to dynamically add IDisposable to IFoo to be proxied.

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

I solved it. Here is the full solution using Reflection Emit.

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;

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

The key was to create a new interface type that is a combination of the two interfaces passed in. Then RealProxy can map the new dynamic interface methods to our MyProxy Invoke method to which we then can invoke the appropriate method.

Look at the call now to CombineType:

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

That then creates a simple in-memory combined interface.

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;

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

Which is passed to the 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;
    }

Output of program:

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

This is not bulletproof yet but is a starter.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

How to combine two tables in R?

분류에서Dev

How to combine two selects or two querys?

분류에서Dev

How to combine the results of two different queries with mongoose?

분류에서Dev

How can I combine these two statements?

분류에서Dev

How can I combine two files on Windows?

분류에서Dev

Bonding two interfaces

분류에서Dev

Combine two queries in Oracle

분류에서Dev

How to pass data between two ViewControllers with TabBarController in Swift

분류에서Dev

OMNET ++, How to pass message between two car in VEINS?

분류에서Dev

Combine/Mix two lists of words

분류에서Dev

Combine two lists of tuples by key

분류에서Dev

combine two different queries into one

분류에서Dev

Combine two commands into a single command

분류에서Dev

DNS server selection between two LAN interfaces

분류에서Dev

Two different Network interfaces simultaniously CentOS

분류에서Dev

How to pass ENV values dynamically in docker file while running docker run command?

분류에서Dev

Two network interfaces assigned to addresses from two DHCP servers

분류에서Dev

How to combine 2 :not class?

분류에서Dev

How to combine angularjs modules?

분류에서Dev

How to combine these 2 formula

분류에서Dev

Combine two dataframes one above the other

분류에서Dev

Python combine two for loops and not over repeat

분류에서Dev

combine two array string to make a list

분류에서Dev

Combine two POSTs using global variables

분류에서Dev

combine two keys to one key in mongodb

분류에서Dev

Is it possible to ping 8.8.8.8 from two interfaces connected to diffrent WANs

분류에서Dev

Connecting two clients on different physical interfaces using smcroute

분류에서Dev

How to pass parameters between two pages (from p:commandLink with redirect=true and view scoped beans)?

분류에서Dev

How can you pass analytics source information between two websites using different versions of Google analytics

Related 관련 기사

  1. 1

    How to combine two tables in R?

  2. 2

    How to combine two selects or two querys?

  3. 3

    How to combine the results of two different queries with mongoose?

  4. 4

    How can I combine these two statements?

  5. 5

    How can I combine two files on Windows?

  6. 6

    Bonding two interfaces

  7. 7

    Combine two queries in Oracle

  8. 8

    How to pass data between two ViewControllers with TabBarController in Swift

  9. 9

    OMNET ++, How to pass message between two car in VEINS?

  10. 10

    Combine/Mix two lists of words

  11. 11

    Combine two lists of tuples by key

  12. 12

    combine two different queries into one

  13. 13

    Combine two commands into a single command

  14. 14

    DNS server selection between two LAN interfaces

  15. 15

    Two different Network interfaces simultaniously CentOS

  16. 16

    How to pass ENV values dynamically in docker file while running docker run command?

  17. 17

    Two network interfaces assigned to addresses from two DHCP servers

  18. 18

    How to combine 2 :not class?

  19. 19

    How to combine angularjs modules?

  20. 20

    How to combine these 2 formula

  21. 21

    Combine two dataframes one above the other

  22. 22

    Python combine two for loops and not over repeat

  23. 23

    combine two array string to make a list

  24. 24

    Combine two POSTs using global variables

  25. 25

    combine two keys to one key in mongodb

  26. 26

    Is it possible to ping 8.8.8.8 from two interfaces connected to diffrent WANs

  27. 27

    Connecting two clients on different physical interfaces using smcroute

  28. 28

    How to pass parameters between two pages (from p:commandLink with redirect=true and view scoped beans)?

  29. 29

    How can you pass analytics source information between two websites using different versions of Google analytics

뜨겁다태그

보관