gpt4 book ai didi

c# - 反射 - 将一个委托(delegate)添加到另一个委托(delegate)的调用列表

转载 作者:太空狗 更新时间:2023-10-29 18:26:45 24 4
gpt4 key购买 nike

我正在尝试将一个委托(delegate)附加到另一个委托(delegate)的调用列表。通过这种方式,我实现了一种对现有事件的 Hook 。我需要连接在每个调用的事件之后运行的东西。

以下示例有效只要类型公开的委托(delegate)和我传入的操作具有完全相同的签名。(On1 和 OnAll 事件都是用 Action 委托(delegate)声明的,因此它可以工作)。

代码:我如何将 Action 与事件修饰符公开的现有委托(delegate) Hook 。

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);
}
}
}

样本:

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() { }
}

问题:当在测试器中使用事件修饰符公开的委托(delegate)没有相同的签名时,我得到一个非常想要的明显异常,其中声明(用我的话说)Action 可以不会添加到 Action<int> 的调用列表中。说得通。

为了清楚起见,我正在描述以下内容:

    public event Action<int> On1;    
public void On1(int i){}

我正在寻找一种方法来创建另一个与 EventHandlerType 类型相同的委托(delegate)。为此,我需要创建一个带有 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);
}
}

最佳答案

这似乎行得通...里面有各种评论...我不确定这是否是最好的方法。我正在构建一个 Expression 树来执行委托(delegate)调用。

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());
}
}
}

关于c# - 反射 - 将一个委托(delegate)添加到另一个委托(delegate)的调用列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30301751/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com