era*_*zap 8 c# reflection delegates
我试图将委托附加到不同代表的调用列表.通过这个我在现有事件上实现了一种钩子.我需要挂钩在每个被调用的事件之后运行的东西.
只要由类型公开的Delegate和传入的Action i具有完全相同的签名,以下示例就可以工作.(On1和OnAll事件都使用Action委托声明,因此它可以工作).
代码:我如何将Action与事件修饰符公开的现有委托挂钩.
public static class ReflectionExtensions
{
public static IEnumerable<EventInfo> GetEvents(this object obj)
{
var events = obj.GetType().GetEvents();
return events;
}
public static void AddHandler(this object obj, Action action)
{
var events = obj.GetEvents();
foreach (var @event in events)
{
@event.AddEventHandler(obj, action);
}
}
}
Run Code Online (Sandbox Code Playgroud)
例子 :
public class Tester
{
public event Action On1;
public event Action On2;
public void RaiseOn1()
{
On1();
}
public void RaiseOn2()
{
On2();
}
}
class Program
{
static void Main(string[] args)
{
var t = new Tester();
t.On1 += On1;
t.On2 += On2;
t.AddHandler(OnAll);
t.RaiseOn1();
t.RaiseOn2();
}
public void On1() { }
public void On2() { }
public void OnAll() { }
}
Run Code Online (Sandbox Code Playgroud)
存在的问题:当用测试仪的事件修饰符暴露的委托不具有相同的签名,我收到了很好想要的,明显的例外其中规定(在我的文字)是Action不能被添加到一个调用列表Action<int>.说得通.
为了清楚起见我正在描述以下内容:
public event Action<int> On1;
public void On1(int i){}
Run Code Online (Sandbox Code Playgroud)
我正在寻找的是一种创建与EventHandlerType相同类型的另一个委托的方法.为了做到这一点,我需要使用EventHandlerType的签名i创建一个方法,该方法将在内部调用操作.
就像是 :
public static void AddHandler(this object obj, Action action)
{
var events = obj.GetEvents();
foreach (var @event in events)
{
// method with the signeture of EventHandlerType which does action();
MethodInfo wrapperMethod = WrapAction(@event.EventHandlerType, action);
Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, wrapperMethod);
@event.AddEventHandler(obj, handler);
}
}
Run Code Online (Sandbox Code Playgroud)
xan*_*tos 10
这似乎有用...里面有各种各样的评论......我不确定这是否是最好的方法.我正在构建一个Expression树来执行委托调用.
public static void AddHandler(this object obj, Action action)
{
var events = obj.GetEvents();
foreach (var @event in events)
{
// Simple case
if (@event.EventHandlerType == typeof(Action))
{
@event.AddEventHandler(obj, action);
}
else
{
// From here: http://stackoverflow.com/a/429564/613130
// We retrieve the parameter types of the event handler
var parameters = @event.EventHandlerType.GetMethod("Invoke").GetParameters();
// We convert it to ParameterExpression[]
ParameterExpression[] parameters2 = Array.ConvertAll(parameters, x => Expression.Parameter(x.ParameterType));
MethodCallExpression call;
// Note that we are "opening" the delegate and using
// directly the Target and the Method! Inside the
// LambdaExpression we will build there won't be a
// delegate call, there will be a method call!
if (action.Target == null)
{
// static case
call = Expression.Call(action.Method);
}
else
{
// instance type
call = Expression.Call(Expression.Constant(action.Target), action.Method);
}
// If you are OK to create a delegate that calls another
// delegate, you can:
// call = Expression.Call(Expression.Constant(action), typeof(Action).GetMethod("Invoke"));
// instead of the big if/else
var lambda = Expression.Lambda(@event.EventHandlerType, call, parameters2);
@event.AddEventHandler(obj, lambda.Compile());
}
}
}
Run Code Online (Sandbox Code Playgroud)