私もこれをやってみたかった、と私は天皇XLIIのアイデアのような何かをかなりクールな方法が出ています。これは表現木を使用しませんが、表現木は+=
または-=
の使用を許可していないため、これはできません。
ただし、.NET Remoting Proxy(またはLinFuやCastle DPなどの他のProxy)を使用して、非常に短い存続プロキシオブジェクトの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>
デリゲートにプロキシオブジェクトを渡すことにあるコードです。私たちは、プロキシになるオブジェクト
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();
}
}
を次のようにこれを使用することで、次のCustomProxy<T>
のコードを、持っている
これを行うと、次の出力が表示されます:
Event to watch = Changed
Event to watch = Changed