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

时间:2022-05-30 21:44:38

Is it possible to pass a function as a parameter in C#? I can do it using the Func or Action classes, but this forces me to declare the entire function signature at once. When I try to use Delegate, I get a compile error saying it can't convert a method group to a Delegate.

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

I'm working on Axial and I'm trying to allow users to call web services. What I'm going for is the ability to create the Visual Studio proxy class and then pass in the generated function. The function signature doesn't matter because the generated code only uses the function name. However, I'd like to pass in the function instead of the name for two reasons: the ability to use the proxy's Url property and a compiler error if the web service doesn't exist or is updated in Visual Studio.

我正在研究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 个解决方案

#1


I think what you want is:

我想你想要的是:

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

Prints "9".

#2


Converting a method group, anonymous method or lambda expression to a delegate requires the compiler to know the exact delegate type. However, you could potentially use lambda expressions and captured variables to make this simpler:

将方法组,匿名方法或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));
}

That basically delays invocation in the normal way, but by wrapping the actual call to Add in a plain Action delegate.

这基本上会以正常方式延迟调用,但是通过将实际调用包装在一个普通的Action委托中添加。

If that doesn't fulfil your requirements, perhaps you can tell us a bit more about what you're really trying to achieve.

如果这不符合您的要求,也许您可​​以告诉我们更多关于您真正想要达到的目标。

EDIT: If this is generated code, you can cast to a Func<...> with the right type arguments - assuming there aren't too many. Other than that, there's no real way of just passing in a method group. There's been occasional calls for an "infoof(...)" operator (like typeof but for members) which would give you a MemberInfo, but that doesn't actually exist.

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

#3


You should have a delegate first

你应该先有一个代表

delegate int Operation(int a, int b)

then it becomes:

然后它变成:

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

No need for any call to Invoke.

无需调用Invoke。

As with dbone I'm unsure why you would need a params[] array. Would you clarify the expanded usage for the params?

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

Also, I'll have to correct something in your question though, because it will cause a compilation error :p

此外,我将不得不纠正你的问题,因为它会导致编译错误:p

#4


please have a look at using delegates here is a great example

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

Delegate Example

why are you using reflection? will there ever be a different number of params? or do you know the method signture will remain constant (also remember C# supports the params[] keyword)

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

params c#

HTH

Bones

#5


Look at Functional Programming Series by Justin Etheredge. You should find solution to your problem there.

看看Justin Etheredge的功能编程系列。您应该在那里找到解决问题的方法。

#6


This is much simple example, to programmer who already familiar with (C/C++/VB.NET/Python)-style pass function by pointer/ref (with C# delegate):

这是一个很简单的例子,对于已经熟悉(C / C ++ / VB.NET/Python)的程序员来说,通过pointer / ref传递函数(使用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


Say If you need to pass the method as parameter as well as you need to catch the return value for further processing . Then the above examples will work fine . But say if you need to pass a method with void return type then you need to create one more version of the InvokeMethod function. Check the example below.

说如果您需要将方法作为参数传递,则需要捕获返回值以进行进一步处理。那么上面的例子就可以了。但是如果你需要传递一个带有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


Something like this ought to work for you:

这样的事应该适合你:

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

Good luck!

#1


I think what you want is:

我想你想要的是:

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

Prints "9".

#2


Converting a method group, anonymous method or lambda expression to a delegate requires the compiler to know the exact delegate type. However, you could potentially use lambda expressions and captured variables to make this simpler:

将方法组,匿名方法或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));
}

That basically delays invocation in the normal way, but by wrapping the actual call to Add in a plain Action delegate.

这基本上会以正常方式延迟调用,但是通过将实际调用包装在一个普通的Action委托中添加。

If that doesn't fulfil your requirements, perhaps you can tell us a bit more about what you're really trying to achieve.

如果这不符合您的要求,也许您可​​以告诉我们更多关于您真正想要达到的目标。

EDIT: If this is generated code, you can cast to a Func<...> with the right type arguments - assuming there aren't too many. Other than that, there's no real way of just passing in a method group. There's been occasional calls for an "infoof(...)" operator (like typeof but for members) which would give you a MemberInfo, but that doesn't actually exist.

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

#3


You should have a delegate first

你应该先有一个代表

delegate int Operation(int a, int b)

then it becomes:

然后它变成:

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

No need for any call to Invoke.

无需调用Invoke。

As with dbone I'm unsure why you would need a params[] array. Would you clarify the expanded usage for the params?

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

Also, I'll have to correct something in your question though, because it will cause a compilation error :p

此外,我将不得不纠正你的问题,因为它会导致编译错误:p

#4


please have a look at using delegates here is a great example

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

Delegate Example

why are you using reflection? will there ever be a different number of params? or do you know the method signture will remain constant (also remember C# supports the params[] keyword)

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

params c#

HTH

Bones

#5


Look at Functional Programming Series by Justin Etheredge. You should find solution to your problem there.

看看Justin Etheredge的功能编程系列。您应该在那里找到解决问题的方法。

#6


This is much simple example, to programmer who already familiar with (C/C++/VB.NET/Python)-style pass function by pointer/ref (with C# delegate):

这是一个很简单的例子,对于已经熟悉(C / C ++ / VB.NET/Python)的程序员来说,通过pointer / ref传递函数(使用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


Say If you need to pass the method as parameter as well as you need to catch the return value for further processing . Then the above examples will work fine . But say if you need to pass a method with void return type then you need to create one more version of the InvokeMethod function. Check the example below.

说如果您需要将方法作为参数传递,则需要捕获返回值以进行进一步处理。那么上面的例子就可以了。但是如果你需要传递一个带有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


Something like this ought to work for you:

这样的事应该适合你:

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

Good luck!