提问人:user31673 提问时间:1/18/2010 最后编辑:Davide Cannizzouser31673 更新时间:1/12/2023 访问量:964749
使用 C 将方法作为参数传递#
Pass Method as Parameter using C#
问:
我有几种方法,它们都具有相同的参数类型和返回值,但名称和块不同。我想将要运行的方法的名称传递给另一个将调用传递的方法。
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 代码,因为我需要定义参数。
答:
您需要使用委托。在本例中,所有方法都采用一个参数并返回一个 - 这最简单地由委托1 表示。因此,您的代码可以通过以下简单的更改变得正确:string
int
Func<string, int>
public bool RunTheMethod(Func<string, int> myMethodName)
{
// ... do stuff
int i = myMethodName("My String");
// ... do more stuff
return true;
}
诚然,代表们的权力远不止于此。例如,使用 C# 时,您可以从 lambda 表达式创建委托,因此可以通过以下方式调用您的方法:
RunTheMethod(x => x.Length);
这将创建一个匿名函数,如下所示:
// 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;
}
然后将该委托传递给方法。RunTheMethod
您可以将委托用于事件订阅、异步执行、回调 - 各种事情。非常值得一读,特别是如果您想使用 LINQ。我有一篇文章主要是关于代表和事件之间的差异,但无论如何你可能会发现它很有用。
1 这只是基于框架中的泛型 Func<T、TResult>
委托类型;您可以轻松地声明自己的:
public delegate int MyDelegateType(string value)
然后将参数改为类型。MyDelegateType
评论
public **delegate** int MyDelegateType(string value)
您应该使用一个委托,它表示一个接受参数并返回一个值的函数:Func<string, int>
string
int
public bool RunTheMethod(Func<string, int> myMethod)
{
// Do stuff
myMethod.Invoke("My String");
// Do stuff
return true;
}
然后这样调用它:
public bool Test()
{
return RunTheMethod(Method1);
}
评论
Test
return RunTheMethod(Method1);
下面是一个不带参数的示例:http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string
带参数:http://www.daniweb.com/forums/thread98148.html#
基本上,您将对象数组以及方法名称传入。然后,将两者与 Invoke 方法一起使用。
params Object[] 参数
评论
可以使用 .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);
}
}
评论
Action
Func<string, int>
Action<int,string>
Func<double,string,int>
double
string
int
public delegate TResult Func<in T1, in T2, (as many arguments as you want), in Tn, out TResult>(T1 arg1, T2 arg2, ..., Tn argn);
从 OP 的例子:
public static int Method1(string mystring)
{
return 1;
}
public static int Method2(string mystring)
{
return 2;
}
试试Action Delegate!然后使用
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"));
评论
InvokeMethod
RunTheMethod
下面是一个示例,可以帮助您更好地理解如何将函数作为参数传递。
假设您有父页面,并且要打开一个子弹出窗口。在父页面中,有一个文本框,应根据子弹出文本框填充该文本框。
在这里,您需要创建一个委托。
父级 .cs 代表声明 公共委托 void FillName(String 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 构造函数中,您需要创建父 //page 的 'delegate type' 参数
儿童弹出.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();
}
然后在呼叫站点上传递委托:
var returnValue = Runner(() => GetUser(99));
评论
虽然公认的答案是绝对正确的,但我想提供另一种方法。
在自己寻找类似问题的解决方案后,我最终来到了这里。
我正在构建一个插件驱动的框架,作为其中的一部分,我希望人们能够将菜单项添加到应用程序菜单到通用列表中,而无需公开实际对象,因为该框架可能会部署在其他没有 UI 对象的平台上。添加有关菜单的一般信息很容易,但允许插件开发人员有足够的自由来创建单击菜单时的回调被证明是一件痛苦的事情。直到我恍然大悟,我试图重新发明轮子,普通菜单调用并触发事件的回调!Menu
Menu
因此,解决方案,尽管听起来很简单,但直到现在我都没有。
只需为每个当前方法创建单独的类,如果必须,可以从基继承,然后为每个方法添加一个事件处理程序。
为了提供一个清晰完整的答案,我将从头开始,然后展示三种可能的解决方案。
简介
所有 .NET 语言(如 C#、F# 和 Visual Basic)都运行在公共语言运行时 (CLR) 之上,CLR 是以公共中间语言 (CIL) 运行代码的 VM,其级别比机器代码高得多。因此,与函数式语言和 JavaScript 不同,方法不是 Assembly 子例程,也不是值;相反,它们是 CLR 识别的符号。不是值,它们不能作为参数传递。这就是为什么 .NET 中有一个特殊的工具。也就是说,代表。
什么是委托?
委托表示方法的句柄(术语句柄优先于指针,因为指针是实现细节)。由于方法不是值,因此 .NET 中必须有一个特殊的类,即 ,它包装了任何方法。它的特别之处在于,与极少数类一样,它需要由 CLR 本身实现,而不能简单地用 .NET 语言编写为类。Delegate
三种不同的解决方案,相同的基本概念
类型不安全的方式
直接使用特殊类。
Delegate
例:
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
例:
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"); }
标准图书馆的方式
或者,可以坚持使用属于 .NET Standard 的委托:Alternatively, you can stick with a delegate that's part of the .NET Standard:
Action
总结了一个无参数方法;void
Action<T1>
使用一个 type 参数包装方法void
T1
;Action<T1, T2>
用 types 和 , 的两个参数来总结一个方法,void
T1
T2
- 等等;
Func<TR>
用返回类型包装一个无参数函数;TR
Func<T1, TR>
使用返回类型和一个 type 参数包装函数TR
T1
;Func<T1, T2, TR>
用返回类型和两个参数分别包装一个函数 和 ;TR
T1
T2
- 等等。
但是,请记住,通过使用此类预定义委托,参数名称不会是自描述的,委托类型的名称对于实例应该执行的操作也没有意义。因此,不要在其目的并非绝对不言而喻的情况下使用它们。
后一种解决方案是大多数人发布的解决方案。为了完整起见,我也在我的回答中提到了它。
评论
Func<T1,T2,TR>
如果要将 Method 作为参数传递,请使用:
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 it as a parameter");
}
class PersonDB
{
string[] list = { "John", "Sam", "Dave" };
public void Process(ProcessPersonDelegate f)
{
foreach(string s in list) f(s);
}
}
第二个类是 Client,它将使用存储类。它有一个 Main 方法,用于创建 PersonDB 的实例,并使用 Client 类中定义的方法调用该对象的 Process 方法。
class Client
{
static void Main()
{
PersonDB p = new PersonDB();
p.Process(PrintName);
}
static void PrintName(string name)
{
System.Console.WriteLine(name);
}
}
我不知道谁可能需要这个,但是如果您不确定如何发送带有委托的 lambda,当使用委托的函数不需要在其中插入任何参数时,您只需要返回值。
因此,您也可以这样做:
public int DoStuff(string stuff)
{
Console.WriteLine(stuff);
}
public static bool MethodWithDelegate(Func<int> delegate)
{
///do stuff
int i = delegate();
return i!=0;
}
public static void Main(String[] args)
{
var answer = MethodWithDelegate(()=> DoStuff("On This random string that the MethodWithDelegate doesn't know about."));
}
如果传递的方法需要接受一个参数并返回一个值,则最好是方法。下面是一个示例。Func
public int Method1(string)
{
// Do something
return 6;
}
public int Method2(string)
{
// Do something different
return 5;
}
public bool RunTheMethod(Func<string, int> myMethodName)
{
// Do stuff
int i = myMethodName("My String");
Console.WriteLine(i); // This is just in place of the "Do more stuff"
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
在此处阅读文档
但是,如果作为参数传递的方法不返回任何内容,则还可以使用 .它最多支持 16 个参数用于传递的方法。下面是一个示例。Action
public int MethodToBeCalled(string name, int age)
{
Console.WriteLine(name + "'s age is" + age);
}
public bool RunTheMethod(Action<string, int> myMethodName)
{
// Do stuff
myMethodName("bob", 32); // Expected output: "bob's age is 32"
return true;
}
public bool Test()
{
return RunTheMethod(MethodToBeCalled);
}
在此处阅读文档
评论