tôi cũng muốn làm điều này, và tôi đã tìm ra một cách khá mát mẻ mà không một cái gì đó giống như Hoàng đế XLII ý tưởng. Nó không sử dụng cây biểu thức mặc dù, như đã đề cập này không thể được thực hiện như cây biểu thức không cho phép sử dụng +=
hoặc -=
. Tuy nhiên, chúng tôi có thể sử dụng một thủ thuật gọn gàng khi chúng tôi sử dụng .NET Remoting Proxy (hoặc bất kỳ Proxy nào khác như LinFu hoặc Castle DP) để chặn một cuộc gọi đến Add/Remove handler trên một đối tượng proxy rất ngắn ngủi. Vai trò của đối tượng proxy này chỉ đơn giản là có một số phương thức được gọi trên nó, và để cho phép các cuộc gọi phương thức của nó bị chặn, tại thời điểm đó chúng ta có thể tìm ra tên của sự kiện.
này nghe có vẻ lạ nhưng đây là mã (mà bằng cách này chỉ hoạt động nếu bạn có một MarshalByRefObject
hoặc một giao diện cho các đối tượng proxy)
Giả sử chúng ta có giao diện và lớp sau
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);
}
}
Sau đó, chúng tôi có thể có một lớp học rất đơn giản mà mong đợi một đại biểu Action<T>
sẽ được thông qua một số trường hợp của T
.
Đây là mã
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()));
}
}
Bí quyết là để vượt qua các đối tượng proxy cho Action<T>
đại biểu được cung cấp.
đâu chúng ta có CustomProxy<T>
mã sau, người chặn cuộc gọi đến +=
và -=
trên đối tượng 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;
}
}
Và sau đó tất cả chúng ta những gì còn lại là sử dụng này như sau
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();
}
}
Làm như vậy, tôi sẽ thấy kết quả này:
Event to watch = Changed
Event to watch = Changed