3

RealProxy ベース コンストラクタの呼び出しでは、プロキシされるターゲット オブジェクトの Type を渡します。私がやりたいのは、プロキシされた型にインターフェイスを動的に追加して、結果のプロキシされた型を追加のインターフェイスにキャストできるようにすることです。

例えば:

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

本質的に、プロキシされるように動的に追加IDisposableするには、このメソッドをどのように実装しますか。IFoo

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インターフェイスによって定義されるメソッドの 1 つにbool CanCastTo(Type type, object o). このメソッドは、プロキシ オブジェクトを他の型にキャストしようとするたびに呼び出されます。キャスト操作の「ターゲット」タイプには、typeパラメーターを介してアクセスできます。

したがって、プロキシが複数のインターフェースを「実装」できるようにするには、サポートしたいタイプtrueのメソッドから返すだけです。CanCastTo()

RealProxyキャスト後、透過プロキシでのメソッド呼び出しは引き続き同じインスタンスによって受信されることに注意してください。

より詳細な議論については、次の MSDN 記事を参照してください: .NET Remoting と COM Interop を使用してカスタム マーシャリングの実装を作成する

完全な例を次に示します。

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

私はそれを解決しました。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;

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

鍵は、渡された 2 つのインターフェイスの組み合わせである新しいインターフェイス タイプを作成することでした。その後、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 に答える