我想动态创建一个代理类。 我知道有一些很不错的框架存在,要做到这一点,但是这纯粹是作为一个学习锻炼,想自己做一个宠物项目。
如果,例如,我有下面的类实现一个接口:
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?
看一看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
您可以使用动态对象所描述的这个问题 ,但对于一个动态生成的,强类型的对象,你必须使用Reflection.Emit
,因为你嫌。 此博客已呈现出类型的动态创建和实例化的示例代码。
我已阅读, 罗斯林具有的功能,这使得动态代理更容易创造,所以也许看看那里。
也许我误解了这个问题,如何构造?
class ProxyClass : IMyInterface
{
public ProxyClass(IMyInterface someInterface)
{
RealClass = someInterface;
}
// Your other code...
}
我不建议这样做。 通常你用一些知名库,如城堡或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();
}
}