私もこれをやりたかったのですが、皇帝 42 世のアイデアのようなことを行うかなりクールな方法を思いつきました。ただし、前述のように、式ツリーはまたはの使用を許可していないため、式ツリーは使用しませ+=
ん-=
。
ただし、.NET Remoting Proxy (または LinFu や Castle DP などの他のプロキシ) を使用して、有効期間が非常に短いプロキシ オブジェクトで Add/Remove ハンドラの呼び出しをインターセプトする巧妙なトリックを使用できます。このプロキシ オブジェクトの役割は、単純に何らかのメソッドを呼び出すことと、そのメソッド呼び出しをインターセプトできるようにすることです。その時点で、イベントの名前を見つけることができます。
これは奇妙に聞こえますが、コードは次のとおりです(ちなみにMarshalByRefObject
、プロキシされたオブジェクトの または インターフェイスがある場合にのみ機能します)
次のインターフェースとクラスがあるとします
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);
}
}
Action<T>
次に、 のインスタンスを渡すデリゲートを期待する非常に単純なクラスを作成できますT
。
ここにコードがあります
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()));
}
}
秘訣は、プロキシされたオブジェクトをAction<T>
提供されたデリゲートに渡すことです。
次のコードがある場合、誰がプロキシされたオブジェクトへCustomProxy<T>
の呼び出しをインターセプトしますか+=
-=
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;
}
}
あとは、これを次のように使用するだけです
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();
}
}
これを行うと、次の出力が表示されます。
Event to watch = Changed
Event to watch = Changed