从带参数的事件中调用无参数操作
Invoking a no-argument Action from an event that takes arguments
我正在尝试编写一个方便的方法,旨在帮助将通用委托绑定到 class 事件。
这个的关键部分是 class 上的事件需要 1 个或多个参数(例如对象和各种参数),而我希望包装的操作采用 0 个参数。
一个简单的例子是:
public class Test
{
//Other class. <int,bool> is just an example, it could be anything
public event Action<int, bool> MyEvent;
//Helper
public void AddAction(Action a, object cls, string eventName)
{
var evt = cls.GetType().GetEvent(eventName);
//Need some code in here to wrap the action
evt.AddEventHandler(cls, a);
}
}
显然,当我们尝试 运行 时,上面的代码可能会抛出异常。
编辑:我应该详细说明。我知道我可以做到 (a,b) => a()
,但在这种情况下,我无法提前知道事件的类型。
我想要的是能够生成一个新委托,接受 int
、bool
然后在内部调用操作。
我曾尝试编写 DynamicMethod/ILGenerator,但运气不佳,因此我正在寻找有关如何执行此操作的意见和建议。据我所知,IL Generation是唯一的方法。
提前致谢。
我必须重命名您的 var event
代码行:它不会编译,因为 event 是您使用的关键字,而不是在表达式中。你说“我想要的是能够生成一个新的委托,它接受 int、bool,然后在内部调用操作”
以下是我使用匿名委托的方法。我正在编辑我以前的 post 以更正错误。
假设您的 MyEvent 将与某些事件处理代码相关联,例如:
public void HookUpTheEventWithTheHandler()
{
MyEvent += MyEventHandler;
}
public void MyEventHandler(int x, bool condition)
{
// Do some processing here....
}
因此我假设下一个它不会为 null:
我的 AddAction 方法可能如下所示:
public void AddAction(Action<int,bool> a, object cls, string eventName)
{
var eventVar = cls.GetType().GetEvent(eventName);
a += delegate(int x, bool condition)
{
MyEvent(x, condition);
};
eventVar.AddEventHandler(cls, a);
}
现在,如果您事先不知道类型,那么您可能需要使用 generecity。
这是我的做法
public class Test<I, B> {
....
public event Action<I, B> MyEvent2;
public void AddAction2(Action<I, B> a, object cls, string eventName)
{
var eventVar = cls.GetType().GetEvent(eventName);
a += delegate(I x, B condition)
{
MyEvent2(x, condition);
};
eventVar.AddEventHandler(cls, a);
}
我花了很多时间来解决这个问题,最后又回到了 Linq 表达式。
我花了一段时间才意识到 DynamicMethod 的主要问题是它没有作用域。当它被构建时,它可以被认为是一组静态指令,因此,它不知道 'this' 是什么(除非你将它作为参数传递)。
我最后做的是用预期的参数编译一个表达式,并在委托上调用预期的方法。
下面是一些示例代码:
public static class AnonymousAction
{
public static Delegate WrapDelegate(Action action, Type targetType)
{
var invoke = targetType.GetMethod ("Invoke");
if (invoke == null)
throw new ArgumentException ("ofType must be delegate");
var parameters = invoke.GetParameters ();
var expressionParams = new ParameterExpression[parameters.Length];
for (int i=0; i<parameters.Length; ++i)
{
expressionParams [i] = Expression.Parameter (parameters [i].ParameterType);
}
var call = Expression.Call (
Expression.Constant(action),
typeof(Action).GetMethod ("Invoke")
);
return Expression.Lambda (targetType, call, expressionParams).Compile ();
}
}
public class MyReceiver
{
public event Action<MyReceiver, int> OnAction;
public void Do()
{
OnAction (this, 22);
}
}
public class Test
{
public void Run()
{
Action onAction = () => {
Console.WriteLine ("Did something");
};
var receiver = new MyReceiver ();
var evt = receiver.GetType ().GetEvent ("OnAction");
evt.AddEventHandler (receiver, AnonymousAction.WrapDelegate (onAction, evt.EventHandlerType));
receiver.Do ();
}
}
static void Main()
{
var t = new Test ();
t.Run ();
}
我正在尝试编写一个方便的方法,旨在帮助将通用委托绑定到 class 事件。
这个的关键部分是 class 上的事件需要 1 个或多个参数(例如对象和各种参数),而我希望包装的操作采用 0 个参数。
一个简单的例子是:
public class Test
{
//Other class. <int,bool> is just an example, it could be anything
public event Action<int, bool> MyEvent;
//Helper
public void AddAction(Action a, object cls, string eventName)
{
var evt = cls.GetType().GetEvent(eventName);
//Need some code in here to wrap the action
evt.AddEventHandler(cls, a);
}
}
显然,当我们尝试 运行 时,上面的代码可能会抛出异常。
编辑:我应该详细说明。我知道我可以做到 (a,b) => a()
,但在这种情况下,我无法提前知道事件的类型。
我想要的是能够生成一个新委托,接受 int
、bool
然后在内部调用操作。
我曾尝试编写 DynamicMethod/ILGenerator,但运气不佳,因此我正在寻找有关如何执行此操作的意见和建议。据我所知,IL Generation是唯一的方法。
提前致谢。
我必须重命名您的 var event
代码行:它不会编译,因为 event 是您使用的关键字,而不是在表达式中。你说“我想要的是能够生成一个新的委托,它接受 int、bool,然后在内部调用操作”
以下是我使用匿名委托的方法。我正在编辑我以前的 post 以更正错误。
假设您的 MyEvent 将与某些事件处理代码相关联,例如:
public void HookUpTheEventWithTheHandler()
{
MyEvent += MyEventHandler;
}
public void MyEventHandler(int x, bool condition)
{
// Do some processing here....
}
因此我假设下一个它不会为 null:
我的 AddAction 方法可能如下所示:
public void AddAction(Action<int,bool> a, object cls, string eventName)
{
var eventVar = cls.GetType().GetEvent(eventName);
a += delegate(int x, bool condition)
{
MyEvent(x, condition);
};
eventVar.AddEventHandler(cls, a);
}
现在,如果您事先不知道类型,那么您可能需要使用 generecity。
这是我的做法
public class Test<I, B> {
....
public event Action<I, B> MyEvent2;
public void AddAction2(Action<I, B> a, object cls, string eventName)
{
var eventVar = cls.GetType().GetEvent(eventName);
a += delegate(I x, B condition)
{
MyEvent2(x, condition);
};
eventVar.AddEventHandler(cls, a);
}
我花了很多时间来解决这个问题,最后又回到了 Linq 表达式。
我花了一段时间才意识到 DynamicMethod 的主要问题是它没有作用域。当它被构建时,它可以被认为是一组静态指令,因此,它不知道 'this' 是什么(除非你将它作为参数传递)。
我最后做的是用预期的参数编译一个表达式,并在委托上调用预期的方法。
下面是一些示例代码:
public static class AnonymousAction
{
public static Delegate WrapDelegate(Action action, Type targetType)
{
var invoke = targetType.GetMethod ("Invoke");
if (invoke == null)
throw new ArgumentException ("ofType must be delegate");
var parameters = invoke.GetParameters ();
var expressionParams = new ParameterExpression[parameters.Length];
for (int i=0; i<parameters.Length; ++i)
{
expressionParams [i] = Expression.Parameter (parameters [i].ParameterType);
}
var call = Expression.Call (
Expression.Constant(action),
typeof(Action).GetMethod ("Invoke")
);
return Expression.Lambda (targetType, call, expressionParams).Compile ();
}
}
public class MyReceiver
{
public event Action<MyReceiver, int> OnAction;
public void Do()
{
OnAction (this, 22);
}
}
public class Test
{
public void Run()
{
Action onAction = () => {
Console.WriteLine ("Did something");
};
var receiver = new MyReceiver ();
var evt = receiver.GetType ().GetEvent ("OnAction");
evt.AddEventHandler (receiver, AnonymousAction.WrapDelegate (onAction, evt.EventHandlerType));
receiver.Do ();
}
}
static void Main()
{
var t = new Test ();
t.Run ();
}