strategy responsibility pattern example dofactory c# .net reflection proxy

responsibility - state pattern c#



Creando dinĂ¡micamente una clase proxy (4)

Eche un vistazo a System.Runtime.Remoting.Proxies.RealProxy . Puede usar esto para crear una instancia que parece ser el tipo de destino desde la perspectiva de la persona que llama. RealProxy.Invoke proporciona un punto desde el que puede invocar simplemente el método de destino en el tipo subyacente o realizar un procesamiento adicional antes / después de la llamada (registro, por ejemplo).

Aquí hay un ejemplo de un proxy que se registra en la consola antes / después de cada invocación de método:

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

Así es como lo usarías:

IMyInterface intf = LoggingProxy<IMyInterface>.Create(new MyClass()); intf.MyProcedure();

La salida a la consola sería entonces:

Antes de invocar: MyProcedure
Hola Mundo
Después de invocar: MyProcedure

Intento crear una clase proxy de forma dinámica. Sé que hay algunos marcos muy buenos para hacer esto, pero este es un proyecto puramente como un ejercicio de aprendizaje, por lo que me gustaría hacerlo yo mismo.

Si, por ejemplo, tengo la siguiente clase implementando una interfaz:

interface IMyInterface { void MyProcedure(); } class MyClass : IMyInterface { void MyProcedure() { Console.WriteLine("Hello World"); } }

Para interceptar métodos a esta clase para registrarlos, estoy creando otra clase (mi versión de una clase proxy) que implementa la misma interfaz pero contiene una referencia a la clase ''real''. Esta clase realiza una acción (por ejemplo, registro) y luego llama al mismo método en la clase real.

Por ejemplo:

class ProxyClass : IMyInterface { private IMyInterface RealClass { get; set; } void MyProcedure() { // Log the call Console.WriteLine("Logging.."); // Call the ''real'' method RealClass.MyProcedure(); } }

La persona que llama luego llama a todos los métodos en la clase de proxy (estoy usando un contenedor de IoC casera básico para inyectar la clase de proxy en lugar de la clase real). Estoy usando este método porque me gustaría poder cambiar RealClass en tiempo de ejecución a otra clase que implemente la misma interfaz.

¿Hay alguna manera de crear ProxyClass en tiempo de ejecución y llenar su propiedad RealClass para que pueda usarse como un proxy para la clase real? ¿Hay una manera simple de hacer esto o necesito usar algo como Reflection.Emit y generar MSIL?


No recomendaría hacer esto. Usualmente usas algunas bibliotecas conocidas como Castle o EntLib. Para algunas clases complicadas puede ser todo un reto generar dinámicamente un proxy. Aquí hay un ejemplo de hacer eso usando el polimorfismo "Es". Para esto, debes declarar todos tus métodos en la base como virtuales. La forma en que intentaste hacer esto ("Has") también es posible, pero a mí me parece más complicado.

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


Puede usar objetos dinámicos como se describe en esta pregunta , pero para un objeto fuertemente generado generado dinámicamente tendrá que usar Reflection.Emit , como sospechaba. Este blog tiene un código de ejemplo que muestra la creación dinámica y creación de instancias de un Tipo.

He leído que Roslyn tiene funciones que facilitan la creación de proxies dinámicos, así que tal vez eche un vistazo allí también.


Tal vez he entendido mal la pregunta, ¿qué tal un constructor?

class ProxyClass : IMyInterface { public ProxyClass(IMyInterface someInterface) { RealClass = someInterface; } // Your other code... }