我有几个方法都具有相同的参数类型和返回值,但名称和块不同。我想将要运行的方法的名称传递给另一个将调用传递的方法的方法。
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代码,因为我需要定义参数。
您需要使用代理。在这种情况下,所有方法都接受一个字符串参数并返回一个int-这最简单地由Func<string,int>delegate1表示。因此,您的代码可以通过以下简单的更改变得正确:
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类型。
根据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"));
下面是一个示例,它可以帮助您更好地理解如何将函数作为参数传递。
假设您有父页面,并且希望打开子弹出窗口。在父页面中有一个文本框,应该根据子弹出文本框填充。
这里需要创建一个代理。
父.cs//代表声明公共委托void FillName(String FirstName);
现在创建一个函数,该函数将填充文本框,函数应映射委托
//parameters
public void Getname(String ThisName)
{
txtname.Text=ThisName;
}
现在单击按钮,您需要打开一个Child弹出窗口。
private void button1_Click(object sender, RoutedEventArgs e)
{
ChildPopUp p = new ChildPopUp (Getname) //pass function name in its constructor
p.Show();
}
在ChildPopUp构造函数中,您需要创建父//页的“委托类型”参数
儿童PopUp.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;
}
为了提供一个清晰完整的答案,我将从一开始就展示三种可能的解决方案。
简介
所有.NET语言(如C#、F#和Visual Basic)都运行在公共语言运行库(CLR)之上,该运行库是一个运行公共中间语言(CIL)代码的VM,其级别远高于机器代码。与函数语言和JavaScript不同,方法不是汇编子程序,也不是值;相反,它们是CLR识别的符号。它们不是值,不能作为参数传递。这就是为什么.NET中有一个特殊的工具,那就是委托。
什么是代表?
委托代表一个方法的句柄(句柄这个术语比指针更可取,因为后者是一个实现细节)。由于方法不是值,所以.NET中必须有一个特殊的类,即Delegate,它包装任何方法。它的特殊之处在于,像极少数类一样,它需要由CLR本身实现,不能简单地用.NET语言将其写成类。
三种不同的解决方案,相同的基本概念
类型–不安全方式直接使用委托特殊类。例子:静态void MyMethod(){Console.WriteLine(“我被委托特殊类调用了!”);}静态void CallAnyMethod(委托您的方法){yourMethod.DynamicInvoke(新对象[]{/*要传递的参数数组*/});}静态void Main(){CallAnyMethod(MyMethod);}这里的缺点是代码类型不安全,允许动态传递参数,没有约束。自定义方式除了Delegate特殊类之外,委托的概念还扩展到自定义委托,即委托关键字前面的方法声明。它们以与“正常”方法调用相同的方式进行类型检查,从而生成类型安全的代码。例子:委托void PrintDelegate(字符串提示);静态void PrintSomewhere(PrintDelegate打印,字符串提示){打印(提示);}静态void PrintOnConsole(字符串提示){Console.WriteLine(提示符);}静态void PrintOnScreen(字符串提示){MessageBox.Show(提示);}静态void Main(){PrintSomewhere(PrintOnConsole,“按键获取消息”);Console.Read();PrintSomewhere(PrintOnScreen,“你好世界”);}标准库的方式或者,您可以使用.NET标准的一部分委托:Action包装了一个无参数的void方法;Action<T1>用一个T1类型的参数包装void方法;Action<T1,T2>分别使用类型T1和T2的两个参数包装了一个void方法,等等Func<TR>用TR返回类型包装无参数函数;Func<T1,TR>用TR返回类型和一个T1类型的参数包装函数;Func<T1,T2,TR>包装了一个具有TR返回类型和两个参数类型T1和T2的函数;等等但是,请记住,通过使用这些预定义的委托,参数名称不会自我描述,委托类型的名称也不会对实例应该做什么有意义。因此,不要在其目的并非绝对不言自明的上下文中使用它们。
后一种解决方案是大多数人发布的解决方案。为了完整起见,我在回答中也提到了这一点。
class PersonDB
{
string[] list = { "John", "Sam", "Dave" };
public void Process(ProcessPersonDelegate f)
{
foreach(string s in list) f(s);
}
}
第二个类是Client,它将使用存储类。它有一个创建PersonDB实例的Main方法,并使用Client类中定义的方法调用该对象的Process方法。
class Client
{
static void Main()
{
PersonDB p = new PersonDB();
p.Process(PrintName);
}
static void PrintName(string name)
{
System.Console.WriteLine(name);
}
}
如果传递的方法需要接受一个参数并返回一个值,那么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);
}
阅读此处的文档