在对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
,除了IDisposable
之外,我还需要向IFoo
基础构造函数调用发送RealProxy
从本质上讲,如何实现此方法以动态地将IDisposable
添加到IFoo
进行代理。
private static Type CombineType(Type type1, Type type2)
{
// How to implement this method, Reflection.Emit????
throw new NotImplementedException();
}
答案 0 :(得分:8)
有一种非常简单的内置方法可以实现这一目标。但是,如果一个人不知道它,它实际上是不可发现的: - )
为了能够控制哪些强制转换操作在从某个RealProxy
派生类获得的透明代理上有效,RealProxy
需要实现一个额外的接口,即{{3 }}
IRemotingTypeInfo
接口定义的方法之一是bool CanCastTo(Type type, object o)
。每次尝试将代理对象转换为其他类型时,都会调用此方法;可以通过type
参数访问强制转换操作的“目标”类型。
因此,要允许您的代理“实现”多个接口,只需从您希望支持的类型的true
方法返回CanCastTo()
。
请注意,在转换后,透明代理上的方法调用仍由同一RealProxy
实例接收。
要进行更深入的讨论,您可以阅读此MSDN文章:IRemotingTypeInfo
这是一个完整的例子:
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;
}
}
答案 1 :(得分: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;
//////////////////////////////////////////////
}
}
}
关键是创建一个新的接口类型,它是传入的两个接口的组合。然后,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 . . .
这不是防弹,但它是首发。