C# 动态创建代理类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15733900/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dynamically creating a proxy class
提问by Dave S
I am trying to create a proxy class dynamically. I know there are some very good frameworks out there to do this but this is purely a pet project as a learning exercise so would like to do it myself.
我正在尝试动态创建代理类。我知道有一些非常好的框架可以做到这一点,但这纯粹是一个作为学习练习的宠物项目,所以我想自己做。
If, for example, I have the following class implementing an interface:
例如,如果我有以下实现接口的类:
interface IMyInterface
{
void MyProcedure();
}
class MyClass : IMyInterface
{
void MyProcedure()
{
Console.WriteLine("Hello World");
}
}
To intercept methods to this class in order to log them, I am creating another class (my version of a proxy class) which implements the same interface but contains a reference to the 'real' class. This class performs an action (e.g. logging) and then calls the same method on the real class.
为了拦截此类的方法以记录它们,我正在创建另一个类(我的代理类版本),它实现了相同的接口但包含对“真实”类的引用。这个类执行一个动作(例如记录),然后在真实的类上调用相同的方法。
For example:
例如:
class ProxyClass : IMyInterface
{
private IMyInterface RealClass { get; set; }
void MyProcedure()
{
// Log the call
Console.WriteLine("Logging..");
// Call the 'real' method
RealClass.MyProcedure();
}
}
The caller then calls all methods on the proxy class instead (I am using a basic home-brew IoC container to inject the proxy class in place of the real class). I am using this method because I would like to be able to swap out RealClass
at run time to another class implementing the same interface.
然后调用者调用代理类上的所有方法(我使用一个基本的自制 IoC 容器来注入代理类而不是真正的类)。我使用这种方法是因为我希望能够RealClass
在运行时切换到另一个实现相同接口的类。
Is there a way to create ProxyClass
at run time and populate its RealClass
property so it can be used as a proxy for the real class? Is there a simple way to do this or do I need to use something like Reflection.Emit
and generate the MSIL?
有没有办法ProxyClass
在运行时创建并填充其RealClass
属性,以便将其用作真实类的代理?有没有一种简单的方法可以做到这一点,还是我需要使用类似的东西Reflection.Emit
并生成 MSIL?
采纳答案by bradmo
Have a look at System.Runtime.Remoting.Proxies.RealProxy. You can use this to create an instance that appears to be the target type from the perspective of the caller. RealProxy.Invoke provides a point from which you can simply invoke the target method on the underlying type or perform additional processing before/after the call (logging, for example).
看看System.Runtime.Remoting.Proxies.RealProxy。您可以使用它来创建一个从调用者的角度来看似乎是目标类型的实例。RealProxy.Invoke 提供了一个点,您可以从该点简单地调用基础类型上的目标方法或在调用之前/之后执行其他处理(例如,记录)。
Here's an example of a proxy that logs to the console before/after each method invocation:
这是在每次方法调用之前/之后登录到控制台的代理示例:
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);
}
}
}
Here is how you would use it:
以下是您将如何使用它:
IMyInterface intf = LoggingProxy<IMyInterface>.Create(new MyClass());
intf.MyProcedure();
The output to console would then be:
控制台的输出将是:
Before invoke: MyProcedure
Hello World
After invoke: MyProcedure
调用前:MyProcedure
Hello World
调用后:MyProcedure
回答by Jason
Maybe I have misunderstood the question, how about a constructor?
也许我误解了这个问题,构造函数怎么样?
class ProxyClass : IMyInterface
{
public ProxyClass(IMyInterface someInterface)
{
RealClass = someInterface;
}
// Your other code...
}
回答by Archeg
I wouldn't recommend doing this. Usually you use some well-known libraries such as Castle or EntLib. For some complicated classes it could be quite a challenge to dynamically generate a proxy. Here is an example of doing that using "Is" polymorphism. For this you have to declare all your methods in base as virtual. The way you were trying to do this ("Has") also possible, but for me looks more complicated.
我不建议这样做。通常您使用一些知名的库,例如 Castle 或 EntLib。对于一些复杂的类,动态生成代理可能是一个很大的挑战。下面是一个使用“Is”多态性来做这件事的例子。为此,您必须将 base 中的所有方法声明为虚拟方法。您尝试执行此操作的方式(“有”)也是可能的,但对我来说看起来更复杂。
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();
}
}
回答by Steve Wilkes
You can use dynamic objects as described in this question, but for a dynamically-generated, strongly-typed object you'll have to use Reflection.Emit
, as you suspected. This bloghas example code showing the dynamic creation and instantiation of a Type.
您可以使用此问题中所述的动态对象,但对于动态生成的强类型对象,您必须使用Reflection.Emit
,正如您所怀疑的。该博客的示例代码显示了类型的动态创建和实例化。
I have read that Roslynhas features which make creation of dynamic proxies easier, so maybe take a look there, too.
我已经读到Roslyn具有使动态代理的创建更容易的功能,所以也可以看看那里。