C# 使用C作为参数的Pass方法#

C# 使用C作为参数的Pass方法#,c#,.net,methods,delegates,C#,.net,Methods,Delegates,我有几个方法,它们都具有相同的参数类型和返回值,但名称和块不同。我想将要运行的方法的名称传递给另一个将调用传递的方法的方法 public int Method1(string) { // Do something return myInt; } public int Method2(string) { // Do something different return myInt; } public bool RunTheMethod([Method Name

我有几个方法,它们都具有相同的参数类型和返回值,但名称和块不同。我想将要运行的方法的名称传递给另一个将调用传递的方法的方法

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);
}
这段代码不起作用,但这就是我正在尝试做的。我不明白的是如何编写RunTheMethod代码,因为我需要定义参数。

您需要使用委托。在本例中,所有方法都采用
string
参数并返回
int
——最简单的表示方式是
Func
delegate1。因此,您的代码可以通过以下简单的更改变得正确:

public bool RunTheMethod(Func<string, int> myMethodName)
{
    // ... do stuff
    int i = myMethodName("My String");
    // ... do more stuff
    return true;
}
这将创建一个匿名函数,如下所示:

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

然后将参数改为类型为
MyDelegateType

您应该使用
Func
委托,它表示接受
string
参数并返回
int
值的函数:

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

下面是一个没有参数的示例:

使用参数:

基本上,传入一个对象数组和方法名。然后将这两种方法与Invoke方法一起使用


params Object[]parameters

您可以使用.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);
    }
}
公共类1
{
公共int方法1(字符串输入)
{
//…做点什么
返回0;
}
公共int方法2(字符串输入)
{
//…做点不同的事
返回1;
}
公共bool运行方法(Func myMethodName)
{
//…做事
int i=myMethodName(“我的字符串”);
//…做更多的事情
返回true;
}
公共布尔测试()
{
返回运行方法(方法1);
}
}
来自OP的示例:

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

 public static int Method2(string mystring)
 {
     return 2;
 }
你可以试试动作代理!然后使用

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

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

public static object InvokeMethod(Delegate method, params object[] args)
{
     return method.DynamicInvoke(args);
}
然后简单地调用方法

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

Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));
Console.WriteLine(InvokeMethod(新函数(方法1),“MyString1”);
Console.WriteLine(InvokeMethod(新的Func(Method2),“MyString2”);

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

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

这里您需要创建一个委托

Parent.cs //代表声明 公共委托void FillName(字符串FirstName)

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

//parameters
public void Getname(String ThisName)
{
     txtname.Text=ThisName;
}
现在点击按钮,您需要打开一个子弹出窗口

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

         p.Show();

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

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;
    }
解决方案包括,用于存储要调用的方法。定义将委托作为参数的方法

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

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

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

所以这个解决方案,就像你意识到的那样简单,直到现在我都没有找到


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

为了提供一个清晰完整的答案,我将从一开始就开始,然后提出三种可能的解决方案


简介

所有运行在CLR(公共语言运行库)之上的语言,如C++语言、F语言和Visual Basic,都在运行比机器代码更高级代码的VM下工作,而C语言和C++语言则被编译为机器语言。与JavaScript以及大多数函数式语言不同,方法不是汇编子例程,也不是值;相反,它们是CLR识别的定义。因此,您不能认为将方法作为参数传递,因为方法本身不会生成任何值,因为它们不是表达式而是语句,存储在生成的程序集中。此时,您将面对代理


代表是什么? 委托表示方法的句柄(句柄一词比指针更可取,因为后者是一个实现-细节)。由于方法不是一个值,因此.NET中必须有一个特殊的类,即
delegate
,它封装了任何方法。它的特殊之处在于,与极少数类一样,它需要由CLR本身实现,而不能由自己实现

请看以下示例:

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

三种不同的解决方案,相同的基本概念:
  • 类型–不安全方式
    直接使用
    委托
    特殊类的方法与上面的示例相同。这里的缺点是您的代码是类型-不安全的,允许动态传递参数,没有约束

  • 定制方式
    除了
    Delegate
    特殊类之外,委托的概念还扩展到自定义委托,自定义委托是在
    Delegate
    关键字前面的方法声明。它们是类型-检查相同
        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;
        }
    
    public static T Runner<T>(Func<T> funcToRun)
    {
        // Do stuff before running function as normal
        return funcToRun();
    }
    
    var returnValue = Runner(() => GetUser(99));
    
    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);
    }
    
    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");
    }
    
    using System;
    
    public void Method1()
    {
        CallingMethod(CalledMethod);
    }
    
    public void CallingMethod(Action method)
    {
        method();   // This will call the method that has been passed as parameter
    }
    
    public void CalledMethod()
    {
        Console.WriteLine("This method is called by passing parameter");
    }
    
    class PersonDB
    {
      string[] list = { "John", "Sam", "Dave" };
      public void Process(ProcessPersonDelegate f)
      {
        foreach(string s in list) f(s);
      }
    }
    
    class Client
    {
      static void Main()
      {
        PersonDB p = new PersonDB();
        p.Process(PrintName);
      }
      static void PrintName(string name)
      {
        System.Console.WriteLine(name);
      }
    }