使用 C# 将方法作为参数传递

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2082615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 23:22:21  来源:igfitidea点击:

Pass Method as Parameter using C#

c#.netmethodsdelegates

提问by user31673

I have several methods all with the same signature (parameters and return values) but different names and the internals of the methods are different. I want to pass the name of the method to run to another method that will invoke the passed in method.

我有几个方法都具有相同的签名(参数和返回值),但不同的名称和方法的内部结构是不同的。我想将要运行的方法的名称传递给另一个将调用传入方法的方法。

public int Method1(string)
{
    ... do something
    return myInt;
}

public int Method2(string)
{
    ... do something different
    return myInt;
}

public bool RunTheMethod([Method Name passed in here] myMethodName)
{
    ... do stuff
    int i = myMethodName("My String");
    ... do more stuff
    return true;
}

public bool Test()
{
    return RunTheMethod(Method1);
}

This code does not work but this is what I am trying to do. What I don't understand is how to write the RunTheMethod code since I need to define the parameter.

这段代码不起作用,但这就是我想要做的。我不明白的是如何编写 RunTheMethod 代码,因为我需要定义参数。

采纳答案by Egil Hansen

You can use the Func delegate in .net 3.5 as the parameter in your RunTheMethod method. The Func delegate allows you to specify a method that takes a number of parameters of a specific type and returns a single argument of a specific type. Here is an example that should work:

您可以使用 .net 3.5 中的 Func 委托作为 RunTheMethod 方法中的参数。Func 委托允许您指定一个方法,该方法采用特定类型的多个参数并返回特定类型的单个参数。这是一个应该有效的示例:

public class Class1
{
    public int Method1(string input)
    {
        //... do something
        return 0;
    }

    public int Method2(string input)
    {
        //... do something different
        return 1;
    }

    public bool RunTheMethod(Func<string, int> myMethodName)
    {
        //... do stuff
        int i = myMethodName("My String");
        //... do more stuff
        return true;
    }

    public bool Test()
    {
        return RunTheMethod(Method1);
    }
}

回答by Jon Skeet

You need to use a delegate. In this case all your methods take a stringparameter and return an int- this is most simply represented by the Func<string, int>delegate1. So your code can become correct with as simple a change as this:

您需要使用委托。在这种情况下,您的所有方法都接受一个string参数并返回一个int- 这最简单地由Func<string, int>委托1表示。因此,您的代码可以通过如下简单的更改变得正确:

public bool RunTheMethod(Func<string, int> myMethodName)
{
    // ... do stuff
    int i = myMethodName("My String");
    // ... do more stuff
    return true;
}

Delegates have a lot more power than this, admittedly. For example, with C# you can create a delegate from a lambda expression, so you could invoke your method this way:

诚然,代表拥有比这更多的权力。例如,使用 C#,您可以从lambda 表达式创建委托,因此您可以通过以下方式调用您的方法:

RunTheMethod(x => x.Length);

That will create an anonymous function like this:

这将创建一个匿名函数,如下所示:

// The <> in the name make it "unspeakable" - you can't refer to this method directly
// in your own code.
private static int <>_HiddenMethod_<>(string x)
{
    return x.Length;
}

and then pass that delegate to the RunTheMethodmethod.

然后将该委托传递给该RunTheMethod方法。

You can use delegates for event subscriptions, asynchronous execution, callbacks - all kinds of things. It's well worth reading up on them, particularly if you want to use LINQ. I have an articlewhich is mostlyabout the differences between delegates and events, but you may find it useful anyway.

您可以使用委托进行事件订阅、异步执行、回调——各种事情。非常值得阅读它们,特别是如果您想使用 LINQ。我有一个文章大多是关于委托和事件之间的差异,但你会发现它很有用呢。



1This is just based on the generic Func<T, TResult>delegate type in the framework; you could easily declare your own:

1这只是基于Func<T, TResult>框架中的泛型委托类型;你可以很容易地声明你自己的:

public delegate int MyDelegateType(string value)

and then make the parameter be of type MyDelegateTypeinstead.

然后使参数成为类型MyDelegateType

回答by Bruno Reis

You should use a Func<string, int>delegate, that represents a function taking a stringas argument and returning an int:

你应该使用一个Func<string, int>委托,它代表一个函数,将 astring作为参数并返回一个int

public bool RunTheMethod(Func<string, int> myMethod) {
    // do stuff
    myMethod.Invoke("My String");
    // do stuff
    return true;
}

Then use it:

然后使用它:

public bool Test() {
    return RunTheMethod(Method1);
}

回答by Jeremy Samuel

Here is an example without a parameter: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string

这是一个没有参数的例子:http: //en.csharp-online.net/CSharp_FAQ: _How_call_a_method_using_a_name_string

with params: http://www.daniweb.com/forums/thread98148.html#

带参数:http: //www.daniweb.com/forums/thread98148.html#

you basically pass in an array of objects along with name of method. you then use both with the Invoke method.

您基本上将对象数组与方法名称一起传递。然后将两者与 Invoke 方法一起使用。

params Object[] parameters

params Object[] 参数

回答by MadcapLaugher

If you want the ability to change which method is called at run time I would recommend using a delegate: http://www.codeproject.com/KB/cs/delegates_step1.aspx

如果您希望能够更改在运行时调用的方法,我建议使用委托:http: //www.codeproject.com/KB/cs/delegates_step1.aspx

It will allow you to create an object to store the method to call and you can pass that to your other methods when it's needed.

它将允许您创建一个对象来存储要调用的方法,并且您可以在需要时将其传递给其他方法。

回答by Zain Ali

From OP's example:

从OP的例子:

 public static int Method1(string mystring)
 {
      return 1;
 }

 public static int Method2(string mystring)
 {
     return 2;
 }

You can try Action Delegate! And then call your method using

你可以试试Action Delegate!然后使用调用您的方法

 public bool RunTheMethod(Action myMethodName)
 {
      myMethodName();   // note: the return value got discarded
      return true;
 }

RunTheMethod(() => Method1("MyString1"));

Or

或者

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

Then simply call method

然后简单地调用方法

Console.WriteLine(InvokeMethod(new Func<string,int>(Method1), "MyString1"));

Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));

回答by Shrikant-Divyanet Solution

Here is an example Which can help you better to understand how to pass a function as a parameter.

这是一个示例,它可以帮助您更好地理解如何将函数作为参数传递。

Suppose you have Parentpage and you want to open a child popup window. In the parent page there is a textbox that should be filled basing on child popup textbox.

假设您有页面并且您想打开一个子弹出窗口。在父页面中有一个文本框,应根据子弹出文本框填充。

Here you need to create a delegate.

在这里你需要创建一个委托。

Parent.cs // declaration of delegates public delegate void FillName(String FirstName);

Parent.cs // 委托声明 public delegate void FillName(String FirstName);

Now create a function which will fill your textbox and function should map delegates

现在创建一个函数来填充你的文本框,函数应该映射委托

//parameters
public void Getname(String ThisName)
{
     txtname.Text=ThisName;
}

Now on button click you need to open a Child popup window.

现在点击按钮,你需要打开一个子弹出窗口。

  private void button1_Click(object sender, RoutedEventArgs e)
  {
        ChildPopUp p = new ChildPopUp (Getname) //pass function name in its constructor

         p.Show();

    }

IN ChildPopUp constructor you need to create parameter of 'delegate type' of parent //page

在 ChildPopUp 构造函数中,您需要创建父 //page 的“委托类型”参数

ChildPopUp.cs

ChildPopUp.cs

    public  Parent.FillName obj;
    public PopUp(Parent.FillName objTMP)//parameter as deligate type
    {
        obj = objTMP;
        InitializeComponent();
    }



   private void OKButton_Click(object sender, RoutedEventArgs e)
    {


        obj(txtFirstName.Text); 
        // Getname() function will call automatically here
        this.DialogResult = true;
    }

回答by kravits88

public static T Runner<T>(Func<T> funcToRun)
{
    //Do stuff before running function as normal
    return funcToRun();
}

Usage:

用法:

var ReturnValue = Runner(() => GetUser(99));

回答by Wobbles

While the accepted answer is absolutely correct, I would like to provide an additional method.

虽然接受的答案是绝对正确的,但我想提供一种额外的方法。

I ended up here after doing my own searching for a solution to a similar question. I am building a plugin driven framework, and as part of it I wanted people to be able to add menu items to the applications menu to a generic list without exposing an actual Menuobject because the framework may deploy on other platforms that don't have MenuUI objects. Adding general info about the menu is easy enough, but allowing the plugin developer enough liberty to create the callback for when the menu is clicked was proving to be a pain. Until it dawned on me that I was trying to re-invent the wheel and normal menus call and trigger the callback from events!

在自己寻找类似问题的解决方案后,我最终来到了这里。我正在构建一个插件驱动的框架,作为其中的一部分,我希望人们能够将菜单项添加到应用程序菜单到通用列表中,而无需暴露实际Menu对象,因为该框架可能会部署在其他没有MenuUI 的平台上对象。添加有关菜单的一般信息很容易,但允许插件开发人员有足够的自由来创建单击菜单时的回调被证明是一种痛苦。直到我意识到我正在尝试重新发明轮子和普通菜单调用并触发事件回调!

So the solution, as simple as it sounds once you realize it, eluded me until now.

所以这个解决方案,就像你意识到它时听起来一样简单,直到现在我都没有找到。

Just create separate classes for each of your current methods, inherited from a base if you must, and just add an event handler to each.

只需为当前的每个方法创建单独的类,如果必须,从基类继承,然后为每个方法添加一个事件处理程序。

回答by Davide Cannizzo

For sharing an as complete as possible solution, I'm going to end up with presenting three different ways of doing, but now I'm going to start from the most basic principle.

为了分享尽可能完整的解决方案,我最终会介绍三种不同的做法,但现在我将从最基本的原则开始。



A brief introduction

简要介绍

All languages that run on top of CLR (Common Language Runtime), such as C#, F#, and Visual Basic, work under a VM, which runs the code on a higher level than native languages like C and C++ (which directly compile to machine code). It follows that methods aren't any kind of compiled block, but they are just structured elements that CLR recognizes. Thus, you cannot think to pass a method as a parameter, because methods don't produce any values themselves, as they're not expressions! Rather, they're statements, which are defined in the generated CIL code. So, you'll face the delegate concept.

所有在 CLR(公共语言运行时)之上运行的语言,例如 C#、F# 和 Visual Basic,都在 VM 下工作,VM 在比 C 和 C++(直接编译为机器代码)。因此,方法不是任何类型的编译块,而只是 CLR 识别的结构化元素。因此,您不能认为将方法作为参数传递,因为方法本身不会产生任何值,因为它们不是表达式!相反,它们是在生成的 CIL 代码中定义的语句。因此,您将面临委托概念。



What's a delegate?

什么是代表?

A delegate represents a pointer to a method. As I said above, a method is not a value, hence there's a special class in CLR languages, Delegate, which wraps up any method.

委托表示指向方法的指针。正如我上面所说,方法不是值,因此在 CLR 语言中有一个特殊的类Delegate,它包含任何方法。

Look at the following example:

看下面的例子:

static void MyMethod()
{
    Console.WriteLine("I was called by the Delegate special class!");
}

static void CallAnyMethod(Delegate yourMethod)
{
    yourMethod.DynamicInvoke(new object[] { /*Array of arguments to pass*/ });
}

static void Main()
{
    CallAnyMethod(MyMethod);
}


Three different ways, the same concept behind:

三种不同的方式,背后同样的理念:

  • Way 1
    Use the Delegatespecial class directly as the example above. The problem of this solution is that your code will be unchecked as you pass dynamically your arguments without restricting them to the types of those in the method definition.

  • Way 2
    Besides the Delegatespecial class, the delegate concept spreads to custom delegates, which are definitions of methods preceded by the delegatekeyword, and they behave the same as normal methods. They are thereby checked, so you'll come up with flawlessly safe code.

    Here's an example:

    delegate void PrintDelegate(string prompt);
    
    static void PrintSomewhere(PrintDelegate print, string prompt)
    {
        print(prompt);
    }
    
    static void PrintOnConsole(string prompt)
    {
        Console.WriteLine(prompt);
    }
    
    static void PrintOnScreen(string prompt)
    {
        MessageBox.Show(prompt);
    }
    
    static void Main()
    {
        PrintSomewhere(PrintOnConsole, "Press a key to get a message");
        Console.Read();
        PrintSomewhere(PrintOnScreen, "Hello world");
    }
    
  • Way 3
    Alternatively, you can use a delegate that has already been defined within the .NET Standard:

    • Actionwraps up a voidwith no arguments.
    • Action<T1>wraps up a voidwith one argument.
    • Action<T1, T2>wraps up a voidwith two arguments.
    • And so on...
    • Func<TR>wraps up a function with TRreturn type and with no arguments.
    • Func<T1, TR>wraps up a function with TRreturn type and with one argument.
    • Func<T1, T2, TR>wraps up a function with TRreturn type and with two arguments.
    • And so on...
  • 方式1直接
    使用Delegate特殊类如上例。此解决方案的问题在于,当您动态传递参数而不将它们限制为方法定义中的类型时,您的代码将被取消检查。

  • 方式二
    除了Delegate特殊的类,委托概念扩展到自定义委托,它是delegate关键字前面的方法的定义,它们的行为与普通方法相同。从而检查它们,因此您将提出完美安全的代码。

    下面是一个例子:

    delegate void PrintDelegate(string prompt);
    
    static void PrintSomewhere(PrintDelegate print, string prompt)
    {
        print(prompt);
    }
    
    static void PrintOnConsole(string prompt)
    {
        Console.WriteLine(prompt);
    }
    
    static void PrintOnScreen(string prompt)
    {
        MessageBox.Show(prompt);
    }
    
    static void Main()
    {
        PrintSomewhere(PrintOnConsole, "Press a key to get a message");
        Console.Read();
        PrintSomewhere(PrintOnScreen, "Hello world");
    }
    
  • 方式 3
    或者,您可以使用已在 .NET Standard 中定义的委托:

    • Actionvoid不带参数地结束 a 。
    • Action<T1>void用一个参数结束 a 。
    • Action<T1, T2>包含void两个参数的 a 。
    • 等等...
    • Func<TR>TR返回类型包装一个没有参数的函数。
    • Func<T1, TR>TR返回类型和一个参数包装一个函数。
    • Func<T1, T2, TR>TR返回类型和两个参数包装一个函数。
    • 等等...

(The latter solution is the one most people posted.)

(后一种解决方案是大多数人发布的解决方案。)