从带参数的事件调用无参数Action

时间:2015-03-01 00:52:33

标签: c# delegates closures

我正在尝试编写一个方便的方法,旨在帮助将泛型委托绑定到类事件。

这个的关键部分是,类上的事件需要一个或多个参数(例如对象和各种参数),并且我希望包装的动作采用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(),但在这种情况下,我事先并不知道事件的类型。

我想要的是能够生成一个新的委托,它接收intbool,然后在内部调用该动作。

我试过写一个DynamicMethod / ILGenerator,没有太多运气,所以我正在寻找输入和建议如何做到这一点。据我所知,IL Generation是唯一的方法。

提前致谢。

2 个答案:

答案 0 :(得分:0)

我必须重命名你的var event代码行:它不会编译,因为event是一个关键词,因为你做了而不是在表达式中。你说&#34; 我想要的是能够生成一个新的委托,接受int,bool,然后在内部调用行动&#34;

以下是我如何使用匿名委托进行此操作。我正在编辑我之前的帖子以纠正错误。

假设您的MyEvent将与某些事件处理代码连接起来,如:

 public void HookUpTheEventWithTheHandler()
    {
        MyEvent += MyEventHandler;

    }

    public void MyEventHandler(int x, bool condition)
    {
        // Do some processing here....
    }

因此,我认为接下来不会为空:

我的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);

      }

答案 1 :(得分:0)

我花了很多时间来解决这个问题,最后还是回到了Linq Expressions。

DynamicMethod的主要问题,我花了一段时间才意识到,它没有范围。当它被构建时,它可以被认为是一组静态的指令,因此,它不知道这个&#39;这个&#39;是(除非你把它作为参数传递)。

我最终做的是使用预期的参数编译表达式,并调用委托上的预期方法。

以下是一些示例代码:

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