代码之家  ›  专栏  ›  技术社区  ›  Dan Goldstein

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

  •  55
  • Dan Goldstein  · 技术社区  · 16 年前

    是否可以在C中传递函数作为参数?我可以使用func或action类来实现,但这迫使我一次声明整个函数签名。当我尝试使用委托时,我得到一个编译错误,它说不能将方法组转换为委托。

    我正在工作 Axial 我正试图允许用户调用Web服务。我要做的是能够创建Visual Studio代理类,然后传入生成的函数。函数签名并不重要,因为生成的代码只使用函数名。但是,我希望传递函数而不是名称,原因有两个:使用代理的URL属性的能力,以及如果Web服务不存在或在Visual Studio中更新,则会出现编译器错误。

    
    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 回复  |  直到 7 年前
        1
  •  52
  •   P Daddy    16 年前

    我想你想要的是:

    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”。

        2
  •  46
  •   Jon Skeet    16 年前

    将方法组、匿名方法或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,但实际上并不存在。

        3
  •  4
  •   Jon Limjap    16 年前

    你应该先有一个代表

    delegate int Operation(int a, int b)
    

    然后它变成:

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

    不需要调用任何调用。

    和dbone一样,我不确定为什么需要params[]数组。你能解释一下这些参数的扩展用法吗?

    另外,我还要纠正您的问题,因为它会导致编译错误:p

        4
  •  3
  •   dbones    16 年前

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

    Delegate Example

    你为什么使用反射?是否会有不同数量的参数?或者,您是否知道方法签名将保持不变(还请记住,c支持params[]关键字)

    params c#

    高温高压

    骨头

        5
  •  3
  •   Sampson    13 年前

    Functional Programming Series Justin Etheredge撰文。 你应该在那里找到解决问题的办法。

        6
  •  3
  •   dns    11 年前

    对于已经熟悉的程序员来说,这是一个非常简单的例子。( C/C++/VB.NET/Python )-样式传递函数 指针/参考 C代表 ):

            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);
            }
    
        7
  •  2
  •   takrl cck    13 年前

    假设您需要将方法作为参数传递,并且需要捕获返回值以进行进一步处理。然后上面的例子就可以了。 但是假设您需要传递一个具有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();
    }
    
        8
  •  1
  •   Mark Carpenter    16 年前

    这样的事情应该对你有用:

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

    祝你好运!