如何在C#中将函数作为参数传递?

时间:2008-12-19 05:53:53

标签: c# reflection

是否可以在C#中将函数作为参数传递?我可以使用Func或Action类来完成它,但这迫使我立刻声明整个函数签名。当我尝试使用Delegate时,我收到一个编译错误,说它无法将方法组转换为Delegate。

我正在研究Axial,我正在尝试允许用户调用Web服务。我想要的是能够创建Visual Studio代理类,然后传入生成的函数。函数签名无关紧要,因为生成的代码仅使用函数名称。但是,我想传递函数而不是名称有两个原因:如果Web服务不存在或在Visual Studio中更新,则能够使用代理的Url属性和编译器错误。


public void AlertIt(object o) {
    Axial.DOM.Window.Alert(o.ToString());
}
public void CallAddService() {
    object[] param = new object[] { int.Parse(txtA.Text), int.Parse(txtB.Text) };
    Axial.ServerScript.CallWebService(new WSProxy.WS().Add, param, AlertIt, AlertIt);
}

class Axial.ServerScript {
    public void CallWebService(Delegate method, object[] param, Action<object> successCallback, Action<object> failureCallback) {
        // translate to javascript (already working)
    }
}

8 个答案:

答案 0 :(得分:52)

我认为你想要的是:

static object InvokeMethod(Delegate method, params object[] args){
    return method.DynamicInvoke(args);
}

static int Add(int a, int b){
    return a + b;
}

static void Test(){
    Console.WriteLine(InvokeMethod(new Func<int, int, int>(Add), 5, 4));
}

打印“9”。

答案 1 :(得分:46)

将方法组,匿名方法或lambda表达式转换为委托要求编译器知道确切的委托类型。但是,您可以使用lambda表达式和捕获的变量来简化这一过程:

public void InvokeMethod(Action action)
{
    action();
}

public int Add(int a, int b)
{
    return a + b;
}

public void Test()
{    
    InvokeMethod(() => Add(2, 3));
}

这基本上会以正常方式延迟调用,但是通过将实际调用包装到普通Add委托中的Action

如果这不符合您的要求,也许您可​​以告诉我们您正在努力实现的目标。

编辑:如果这是生成的代码,您可以使用正确的类型参数转换为Func<...> - 假设没有太多。除此之外,没有真正的方法只是传递方法组。偶尔需要一个“infoof(...)”运算符(比如typeof但是对于成员)会给你一个MemberInfo,但实际上并不存在。

答案 2 :(得分:4)

你应该先有一个代表

delegate int Operation(int a, int b)
然后它变成了:

public void InvokeMethod(Operation method, object target, object param)
{
    method((int) target, (int) param);
}

无需调用Invoke。

与dbone一样,我不确定为什么你需要一个params []数组。你会澄清params的扩展用法吗?

另外,我必须更正你问题中的内容,因为它会导致编译错误:p

答案 3 :(得分:3)

请看一下使用代表这里是一个很好的例子

Delegate Example

你为什么要用反射?会不会有不同数量的参数?或者你知道方法signture将保持不变(还记得C#支持params []关键字)

params c#

HTH

答案 4 :(得分:3)

请看Justin Etheredge的Functional Programming Series。 你应该在那里找到问题的解决方案。

答案 5 :(得分:3)

这是一个非常简单的例子,对于已经熟悉( C / C ++ / VB.NET/Python)的程序员来说,通过指针/参考来传递函数(带有 C#delegate ):

        delegate void CALLBACK(String s);
        static void Main(string[] args)
        {

            Get("some string", testfunc);

            Util.pause();
        }

        static void Get(String s, CALLBACK x)
        {
            x(s);
        }


        static void testfunc(String s)
        {
            Console.WriteLine(s);
        }

答案 6 :(得分:2)

Say如果您需要将方法作为参数传递,则需要捕获返回值以进行进一步处理。那么上面的例子就可以了。 但是如果你需要传递一个带有void返回类型的方法,那么你需要再创建一个InvokeMethod函数版本。 请查看以下示例。

private static T retry<T>(Delegate method, params object[] args)
{
    for (int i = 0; i <= 3; i++)
    {
        try
        {
            return (T)method.DynamicInvoke(args);
        }
        catch (Exception ex)
        {
            if (i == 3)
            {
                logMessage(ex.Message);
            }
            Console.WriteLine("Retry count " + i);
            Thread.Sleep(10);
        }
    }
    return default(T);
}

private static void retry2(Delegate method, params object[] args)
{
    for (int i = 0; i <= 3; i++)
    {
        try
        {
            method.DynamicInvoke(args);
            break;
        }
        catch (Exception ex)
        {
            if (i == 3)
            {
                logMessage(ex.Message);
                //return default(T);
            }
            Console.WriteLine("Retry count " + i);
            Thread.Sleep(10);
        }
    }
}
static bool isSuccess = true;
static void logMessage(string msg)
{
    isSuccess = false;
    Console.WriteLine(msg);
}

static int Add(int a, int b)
{
    return a + b;
}

static void Add2(int a, int b)
{
    int c = a + b;
    Console.WriteLine(c);
}

static void Main(string[] args)
{
    int d = retry<int>(new Func<int, int, int>(Add), 6, 7.7);
    Console.Write("  " + d + "\n"+isSuccess);

    retry2(new Action<int, int>(Add2), 45, 60);

    Console.ReadKey();
}

答案 7 :(得分:1)

这样的事应该适合你:

delegate int MyDelegate(int a, int b);
public int Add(int a, int b) {
    return a + b;
}
public void InvokeMethod(Delegate method, object[] param) {
    Console.WriteLine(method.DynamicInvoke(param));
}
public Form1() {       
    InitializeComponent();
    InvokeMethod(new MyDelegate(Add), new object[] { 1, 2 });
}
祝你好运!