我有几个方法都具有相同的参数类型和返回值,但名称和块不同。我想将要运行的方法的名称传递给另一个将调用传递的方法的方法。
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 代码,因为我需要定义参数。
您可以使用 .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);
}
}
您需要使用委托。在这种情况下,您的所有方法都接受一个 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;
}
诚然,代表们的权力远不止于此。例如,使用 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。我有一个article,主要是关于委托和事件之间的差异,但无论如何您可能会发现它很有用。
1 这只是基于框架中的通用 Func<T, TResult>
委托类型;您可以轻松地声明自己的:
public delegate int MyDelegateType(string value)
然后将参数改为 MyDelegateType
类型。
public **delegate** int MyDelegateType(string value)
中是否缺少委托关键字?
从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"));
InvokeMethod
lambda 调用应该是 RunTheMethod
为了提供一个清晰完整的答案,我将从一开始就开始,然后提出三种可能的解决方案。
简介
在 CLR(公共语言运行时)之上运行的所有语言,例如 C#、F# 和 Visual Basic,都在运行比机器代码更高级别代码的 VM 下工作。与 JavaScript 和大多数函数式语言不同,方法不是汇编子例程,也不是值。相反,它们是 CLR 识别的符号。因此,您不能考虑将方法作为参数传递,因为方法本身不会产生任何值,因为它们不是表达式而是语句,它们存储在生成的程序集中。此时,您将面对代表。
什么是代表?
委托代表方法的句柄(术语 handle 应优先于 pointer,因为后者将是实现细节)。由于方法不是值,因此 .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 特殊类之外,委托的概念还扩展到自定义委托,它们是在 delegate 关键字前面的方法声明。它们与方法声明一样经过类型检查,从而产生完美无瑕的安全代码。这是一个例子:delegate void PrintDelegate(string prompt); static void PrintSomewhere(PrintDelegate print, string prompt) { print(prompt); } 静态无效 PrintOnConsole(字符串提示) { Console.WriteLine(提示); } 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 的委托:Action 封装了一个无参数的 void 方法。 Action
Action 封装了一个无参数的 void 方法。
Action
Action
等等……
Func
Func
Func
等等……
后一种解决方案是大多数人发布的解决方案。为了完整起见,我也在我的回答中提到了它。
解决方案涉及Delegates,用于存储要调用的方法。定义一个将委托作为参数的方法,
然后在调用站点上传递委托:
您应该使用
然后以这种方式调用它:
虽然公认的答案是绝对正确的,但我想提供一种额外的方法。
在自己寻找类似问题的解决方案后,我来到了这里。我正在构建一个插件驱动的框架,作为其中的一部分,我希望人们能够将菜单项添加到应用程序菜单的通用列表中,而无需公开实际的
所以解决方案,一旦你意识到它听起来很简单,直到现在我才发现它。
只需为每个当前方法创建单独的类,如果必须从基类继承,然后为每个方法添加一个事件处理程序。
这是一个示例,它可以帮助您更好地理解如何将函数作为参数传递。
假设您有父页面并且您想打开一个子弹出窗口。在父页面中有一个文本框,应该根据子弹出文本框填充。
在这里,您需要创建一个委托。
Parent.cs // 委托声明 public delegate void FillName(String FirstName);
现在创建一个将填充您的文本框的函数,并且函数应该映射委托
现在点击按钮,您需要打开一个子弹出窗口。
在 ChildPopUp 构造函数中,您需要创建父 //page 的“委托类型”参数
ChildPopUp.cs
如果要将 Method 作为参数传递,请使用:
这是一个没有参数的示例:http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string
带参数:http://www.daniweb.com/forums/thread98148.html#
您基本上传入一个对象数组以及方法名称。然后将两者与 Invoke 方法一起使用。
参数 Object[] 参数
第二个类是Client,它将使用存储类。它有一个创建 PersonDB 实例的 Main 方法,并使用 Client 类中定义的方法调用该对象的 Process 方法。
我不知道谁可能需要这个,但如果你不确定如何发送带有委托的 lambda,当使用委托的函数不需要在其中插入任何参数时,你只需要返回值。
所以你也可以这样做:
如果传递的方法需要接受一个参数并返回一个值,
阅读文档here
但是,如果作为参数传递的方法没有返回任何内容,您也可以使用
阅读文档 here
不定期副业成功案例分享 包装了一个带有 TR 返回类型的无参数函数。 Func 包装了一个带有 TR 返回类型的无参数函数。
Func<T1,T2,TR>
public static T Runner<T>(Func<T> funcToRun)
{
// Do stuff before running function as normal
return funcToRun();
}
var returnValue = Runner(() => GetUser(99));
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);
Menu
对象,因为该框架可能会部署在其他平台上t 有 Menu
个 UI 对象。添加有关菜单的一般信息很容易,但是让插件开发人员有足够的自由来创建单击菜单时的回调被证明是一种痛苦。直到我突然意识到我试图重新发明轮子和正常的菜单调用并触发事件的回调!
//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();
}
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;
}
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);
}
}
class Client
{
static void Main()
{
PersonDB p = new PersonDB();
p.Process(PrintName);
}
static void PrintName(string name)
{
System.Console.WriteLine(name);
}
}
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);
}
Action
。对于传递的方法,它最多支持 16 个参数。这是一个例子。 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);
}
关注公众号
想领先一步获取最新的外包任务吗?
立即订阅
Action
而不是Func<string, int>
。Action<int,string>
对应于采用 2 个参数(int 和 string)并返回 void 的方法。Func<double,string,int>
对应于采用 2 个参数(double
和string
)并返回int
的方法。最后指定的类型是返回类型。您可以将此委托用于最多 16 个参数。如果您不知何故需要更多,请将您自己的委托写为public delegate TResult Func<in T1, in T2, (as many arguments as you want), in Tn, out TResult>(T1 arg1, T2 arg2, ..., Tn argn);
。如果我误解了,请纠正我。