demasiado lo que quería hacer esto, y han llegado con una forma muy bueno que hace algo como idea emperador XLII. Sin embargo, no utiliza árboles de Expresión, como se mencionó, esto no se puede hacer ya que los árboles de Expresión no permiten el uso de +=
o -=
.
Sin embargo, podemos utilizar un buen truco donde utilizamos .NET Remoting Proxy (o cualquier otro Proxy como LinFu o Castle DP) para interceptar una llamada al controlador Agregar/Quitar en un objeto proxy de muy corta duración. La función de este objeto proxy es simplemente tener un método invocado y permitir que se intercepten sus llamadas a métodos, en cuyo caso podemos encontrar el nombre del evento.
Esto suena extraño, pero aquí está el código (que por cierto sólo funciona si tiene una interfaz MarshalByRefObject
o de los objetos proxy)
Supongamos que tenemos la siguiente interfaz y la clase
public interface ISomeClassWithEvent {
event EventHandler<EventArgs> Changed;
}
public class SomeClassWithEvent : ISomeClassWithEvent {
public event EventHandler<EventArgs> Changed;
protected virtual void OnChanged(EventArgs e) {
if (Changed != null)
Changed(this, e);
}
}
Entonces podemos tener una clase muy simple que espera un delegado Action<T>
que se aprobará en alguna instancia de T
.
Este es el código
public class EventWatcher<T> {
public void WatchEvent(Action<T> eventToWatch) {
CustomProxy<T> proxy = new CustomProxy<T>(InvocationType.Event);
T tester = (T) proxy.GetTransparentProxy();
eventToWatch(tester);
Console.WriteLine(string.Format("Event to watch = {0}", proxy.Invocations.First()));
}
}
El truco consiste en pasar los objetos proxy al delegado Action<T>
proporcionado.
donde tenemos la CustomProxy<T>
siguiente código, que intercepta la llamada a +=
y -=
en el objeto proxy
public enum InvocationType { Event }
public class CustomProxy<T> : RealProxy {
private List<string> invocations = new List<string>();
private InvocationType invocationType;
public CustomProxy(InvocationType invocationType) : base(typeof(T)) {
this.invocations = new List<string>();
this.invocationType = invocationType;
}
public List<string> Invocations {
get {
return invocations;
}
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
[DebuggerStepThrough]
public override IMessage Invoke(IMessage msg) {
String methodName = (String) msg.Properties["__MethodName"];
Type[] parameterTypes = (Type[]) msg.Properties["__MethodSignature"];
MethodBase method = typeof(T).GetMethod(methodName, parameterTypes);
switch (invocationType) {
case InvocationType.Event:
invocations.Add(ReplaceAddRemovePrefixes(method.Name));
break;
// You could deal with other cases here if needed
}
IMethodCallMessage message = msg as IMethodCallMessage;
Object response = null;
ReturnMessage responseMessage = new ReturnMessage(response, null, 0, null, message);
return responseMessage;
}
private string ReplaceAddRemovePrefixes(string method) {
if (method.Contains("add_"))
return method.Replace("add_","");
if (method.Contains("remove_"))
return method.Replace("remove_","");
return method;
}
}
Y entonces todo lo que queda es usar esto como sigue
class Program {
static void Main(string[] args) {
EventWatcher<ISomeClassWithEvent> eventWatcher = new EventWatcher<ISomeClassWithEvent>();
eventWatcher.WatchEvent(x => x.Changed += null);
eventWatcher.WatchEvent(x => x.Changed -= null);
Console.ReadLine();
}
}
Al hacer esto, veré esta salida:
Event to watch = Changed
Event to watch = Changed