简体   繁体   English

如何在C#中动态调用带有任何签名的方法?

[英]How do you invoke a method with any signature dynamically in C#?

I had a class with some common error handling code, and I wanted to pass in the method and arguments to call, but I couldn't quite come up with the syntax. 我有一个带有一些常见错误处理代码的类,我想传入方法和参数以进行调用,但是我不太想出语法。 What I want to do is roughly this: 我想做的大致是这样的:

private void InvokeHelper(Delegate method, params object[] args)
{
  bool retry = false;

  do
  {
    try
    {
      method.DynamicInvoke(args);
      retry = false;
    }
    catch (MyException ex)
    {
      retry = HandleException(ex);
    }
  } while (retry);
}

and then be able to do things like: 然后能够执行以下操作:

InvokeHelper(foo.MethodA, a, b, c);
InvokeHelper(foo.MethodB, x, y );

This gets a compiler error converting foo.MethodA and foo.MethodB into System.Delegate. 这将导致将foo.MethodA和foo.MethodB转换为System.Delegate的编译器错误。 I came up with the workaround below (and I actually like it better because then I get type checking on my arguments to my methods), but I'm curious if there's a way to do what I was originally trying to do? 我想出了以下解决方法(我实际上更喜欢它,因为这样我就可以对方法的参数进行类型检查了),但是我很好奇是否有一种方法可以做我本来想做的事情? I know I could use foo.GetType().GetMethod("MethodA") and invoke that, but I was trying to avoid reflection. 我知道我可以使用foo.GetType().GetMethod("MethodA")并调用它,但是我试图避免反射。 I mainly just want to understand how methods are dynamically invoked in .net. 我主要只是想了解如何在.net中动态调用方法。

Workaround: 解决方法:

private delegate void EmptyDelegate();

private void InvokeHelper(EmptyDelegate method)
{
  bool retry = false;

  do
  {
    try
    {
      method.Invoke();
      retry = false;
    }
    catch (MyException ex)
    {
      retry = HandleException(ex);
    }
  } while (retry);
}

then call: 然后致电:

InvokeHelper(delegate() { foo.MethodA(a, b, c); });
InvokeHelper(delegate() { foo.MethodB(x, y); });

First off, your signature is 首先,您的签名是

private void InvokeHelper(Delegate method, params object[] args)

Yet you're making the mistake that you have to group your args into an array to call this method: 但是,您犯了一个错误,您必须将args分组到一个数组中才能调用此方法:

InvokeHelper(foo.MethodA, new object[] { a, b, c});

The parms keyword tells the compiler to do this for you; parms关键字告诉编译器为您执行此操作; you can call this method thusly: 您可以这样调用此方法:

InvokeHelper(foo.MethodA, a, b, c);

Second, if you're targeting 3.0 or greater, don't use Delegate, use Action: 其次,如果您的目标是3.0或更高版本,请不要使用Delegate,而应使用Action:

private void InvokeHelper(Action method)

and call it this way: 并这样称呼:

InvokeHelper(()=> MyMethodToInvoke(a, b, c));

which is just an overall better way of doing this. 这只是整体上更好的方法。


As to why you're getting the compiler issue, its because System.Delegates hate us. 至于为什么会遇到编译器问题,这是因为System.Delegates讨厌我们。 Its a simple fact. 这是一个简单的事实。 That, and because there is no implicit cast from method group to Delegate. 那是因为没有从方法组到委托的隐式转换。

Here's a re-write, following Will's advice to use Action: 这是根据Will的建议使用Action进行的重写:

    private void InvokeHelper(Action method)
    {
        bool retry = false;

        do
        {
            try
            {
                method();
                retry = false;
            }
            catch (MyException ex)
            {
                retry = HandleException(ex);
            }
        } while (retry);
    }

    public void Test()
    {
        FooClass foo = new FooClass();
        InvokeHelper( () => foo.MethodA(1, "b", 3) );
        InvokeHelper( () => foo.MethodB(2, "y"));
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM