Action、Func、Predicate 和 Converter 泛型委托详解 .
Action 委托
封装一个方法,该方法不具有参数并且不返回值。
public delegate void Action()
可以使用此委托,而不用显式声明一个自定义的委托来封装方法。该封装的方法必须与此委托定义的方法签名相对应。这意味着该方法不得具有参数和返回值。例:
- using System;
- using System.Windows.Forms;
- public class Name
- {
- private string instanceName;
- public Action ShowName;
- public Show()
- {
- If(ShowName != null)
- ShowName();
- }
- public Name(string name)
- {
- this.instanceName = name;
- }
- public void DisplayToConsole()
- {
- Console.WriteLine(this.instanceName);
- }
- public void DisplayToWindow()
- {
- MessageBox.Show(this.instanceName);
- }
- }
- public class ActionStudy
- {
- public static void Main()
- {
- Name testName = new Name("Koani");
- testName.ShowName = () => testName.DisplayToWindow();
- testName.Show();
- }
- }
using System;
using System.Windows.Forms;
public class Name
{
private string instanceName;
public Action ShowName;
public Show()
{
If(ShowName != null)
ShowName();
}
public Name(string name)
{
this.instanceName = name;
}
public void DisplayToConsole()
{
Console.WriteLine(this.instanceName);
}
public void DisplayToWindow()
{
MessageBox.Show(this.instanceName);
}
}
public class ActionStudy
{
public static void Main()
{
Name testName = new Name("Koani");
testName.ShowName = () => testName.DisplayToWindow();
testName.Show();
}
}
Action<T> 委托
public delegate void Action<T>( T obj )
Action<T> 泛型委托:封装一个方法,该方法只采用一个参数并且不返回值。可以使用此委托以参数形式传递方法,而不用显式声明自定义的委托。该方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数(泛型参数),并且不能返回值。
- using System;
- using System.Windows.Forms;
- public class ActionStudy
- {
- public static void Main()
- {
- Action<string> messageTarget;
- if (Environment.GetCommandLineArgs().Length > 1)
- messageTarget = s => MessageBox.Show(s);
- else
- messageTarget = s => Console.WriteLine(s);
- messageTarget("Hello, World!");
- }
- }
using System;
using System.Windows.Forms;
public class ActionStudy
{
public static void Main()
{
Action<string> messageTarget;
if (Environment.GetCommandLineArgs().Length > 1)
messageTarget = s => MessageBox.Show(s);
else
messageTarget = s => Console.WriteLine(s);
messageTarget("Hello, World!");
}
}
下面的示例演示如何使用 Action(T)委托来打印List(T)对象的内容。在此示例中,使用 Print 方法将列表的内容显示到控制台上。此外,C#示例还演示如何使用匿名方法将内容显示到控制台上。
- using System;
- using System.Collections.Generic;
- class Program
- {
- static void Main()
- {
- Action<string> PrintInConsole = s => Console.WriteLine(s);
- Action<string> PrintInDialog = s=>MessageBox.Show(s);
- List<String> names = new List<String>();
- names.Add("Bruce");
- names.Add("Alfred");
- names.Add("Tim");
- names.Add("Richard");
- names.ForEach(PrintInConsole);
- names.ForEach(PrintInDialog);
- }
- }
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Action<string> PrintInConsole = s => Console.WriteLine(s);
Action<string> PrintInDialog = s=>MessageBox.Show(s);
List<String> names = new List<String>();
names.Add("Bruce");
names.Add("Alfred");
names.Add("Tim");
names.Add("Richard");
names.ForEach(PrintInConsole);
names.ForEach(PrintInDialog);
}
}
泛型委托与直接显示声明自定义委托的示例比较:
1:显示声明自定义委托:
- delegate void DisplayMessage(string message);
- public class TestCustomDelegate
- {
- public static void Main()
- {
- DisplayMessage messageTarget;
- messageTarget = ShowWindowsMessage;
- messageTarget("Hello, World!");
- }
- private static void ShowWindowsMessage(string message)
- {
- MessageBox.Show(message);
- }
- }
delegate void DisplayMessage(string message);
public class TestCustomDelegate
{
public static void Main()
{
DisplayMessage messageTarget;
messageTarget = ShowWindowsMessage;
messageTarget("Hello, World!");
}
private static void ShowWindowsMessage(string message)
{
MessageBox.Show(message);
}
}
2: Action<T> 用法。比起自定义委托,明显可以看出代码简洁了。
- public class TestAction1
- {
- public static void Main()
- {
- Action<string> messageTarget;
- messageTarget = ShowWindowsMessage;
- messageTarget("Hello, World!");
- }
- private static void ShowWindowsMessage(string message)
- {
- MessageBox.Show(message);
- }
- }
public class TestAction1
{
public static void Main()
{
Action<string> messageTarget;
messageTarget = ShowWindowsMessage;
messageTarget("Hello, World!");
}
private static void ShowWindowsMessage(string message)
{
MessageBox.Show(message);
}
}
Action<T1, T2> 委托
封装一个方法,该方法具有两个参数并且不返回值。
可以使用 Action(T1, T2) 委托以参数形式传递方法,而不用显式声明自定义的委托。该
方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有两个均通过值传递给它的参数,并且不能返回值。
public delegate void Action<T,T2>(T1 arg1,T2 arg2)
- using System;
- using System.IO;
- public class ActinStudy
- {
- public static void Main()
- {
- string message1 = "The first line of a message.";
- string message2 = "The second line of a message.";
- Action<string, string> concat;
- if (Environment.GetCommandLineArgs().Length > 1)
- concat = (s1, s2) => {
- StreamWriter writer = null;
- try
- {
- writer = new StreamWriter(Environment.GetCommandLineArgs()[1], false);
- writer.WriteLine("{0}"n{1}", s1, s2);
- }
- catch
- {
- Console.WriteLine("File write operation failed...");
- }
- finally
- {
- if (writer != null) writer.Close();
- }
- };
- else
- concat = (s1, s2) => Console.WriteLine("{0}"n{1}", s1, s2);
- concat(message1, message2);
- }
using System;
using System.IO;
public class ActinStudy
{
public static void Main()
{
string message1 = "The first line of a message.";
string message2 = "The second line of a message.";
Action<string, string> concat;
if (Environment.GetCommandLineArgs().Length > 1)
concat = (s1, s2) => {
StreamWriter writer = null;
try
{
writer = new StreamWriter(Environment.GetCommandLineArgs()[1], false);
writer.WriteLine("{0}"n{1}", s1, s2);
}
catch
{
Console.WriteLine("File write operation failed...");
}
finally
{
if (writer != null) writer.Close();
}
};
else
concat = (s1, s2) => Console.WriteLine("{0}"n{1}", s1, s2);
concat(message1, message2);
}
4. 有3个输入参数返回值为void的委托
Action<T1,T2,T3>委托,封装一个方法,该方法采用三个参数并且不返回值。
可以使用 Action(T1, T2, T3) 委托以参数形式传递方法,而不用显式声明自定义的委托。
该方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有三个均通过值传递给它的参数,并且不能返回值。
public delegate void Action<T1,T2,T3>(T1 arg1,T2 arg2,T3 arg3);
5. 有4个输入参数返回值为void的委托
Action<T1,T2,T3,T4>委托,封装一个方法,该方法具有四个参数并且不返回值。
可以使用 Action(T1, T2, T3, T4)委托以参数形式传递方法,而不用显式声明自定义的委托。封装的方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有四个均通过值传递给它的参数,并且不能返回值。
Func泛型委托
Func系列的委托定义的是返回值的委托。它有多个版本包括没有输入参数,1个输入参数,2个输入参数,3个输入参数,4个输入参数共5个版本这几个版本的原型如下:
Func<TResult> 委托
没有输入参数有返回值(返回值不为void)的委托。封装一个不具有参数但却返回 TResult参数指定的类型值的方法。
可以使用此委托构造一个能以参数形式传递的方法,而不用显式声明自定义的委托。该
方法必须与此委托定义的方法签名相对应。这意味着封装的方法不得具有参数,但必须返回值。
TResult:此委托封装的方法的返回值类型。
public delegate TResult Func<out TResult>()
Func< T,TResult> 委托
封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。
public delegate TResult Func<T, out TResult>(T arg)
下面通过几个例子对比下,就容易知道其用法:
以下例子演示了如何利用委托将字符串转化为大写:
- delegate string ConvertMethod(string inString);
- private static string UppercaseString(string inputString)
- {
- return inputString.ToUpper();
- }
- protected void Page_Load(object sender, EventArgs e)
- {
- //ConvertMethod convertMeth = UppercaseString; 也可以这样写
- ConvertMethod convertMeth = new ConvertMethod(ppercaseString);
- string name = "Dakota";
- Response.Write(convertMeth(name));//通过委托调用UppercaseString方法
- }
delegate string ConvertMethod(string inString);
private static string UppercaseString(string inputString)
{
return inputString.ToUpper();
}
protected void Page_Load(object sender, EventArgs e)
{
//ConvertMethod convertMeth = UppercaseString; 也可以这样写
ConvertMethod convertMeth = new ConvertMethod(ppercaseString);
string name = "Dakota";
Response.Write(convertMeth(name));//通过委托调用UppercaseString方法
}
这段代码很容易理解,定义一个方法UppercaseString,功能很简单:将字符串转化为大写,然后定义一个ConvertMethod的实例来调用这个方法,最后将Dakota转化为大写输出
接下来改进一下,将Page_Load中的 ConvertMethod convertMeth = new ConvertMethod(ppercaseString)改为Func 泛型委托,即:
- protected void Page_Load(object sender, EventArgs e)
- {
- Func<string, string> convertMeth = UppercaseString;
- string name = "Dakota";
- Response.Write(convertMeth(name));
- }
protected void Page_Load(object sender, EventArgs e)
{
Func<string, string> convertMeth = UppercaseString;
string name = "Dakota";
Response.Write(convertMeth(name));
}
运行后,与前一种写法结果完全相同,这里再联系官方解释想一想,Func<string, string>即为封闭一个string类型的参数,并返回string类型值的方法
当然,我们还可以利用匿名委托,将这段代码写得更简洁:
- protected void Page_Load(object sender, EventArgs e)
- {
- Func<string, string> convertMeth = delegate(string s){ return s.ToUpper(); };
- string name = "Dakota";
- Response.Write(convertMeth(name));
- }
protected void Page_Load(object sender, EventArgs e)
{
Func<string, string> convertMeth = delegate(string s){ return s.ToUpper(); };
string name = "Dakota";
Response.Write(convertMeth(name));
}
怎么样?是不是清爽很多了,但这并不是最简洁的写法,如果利用Lambda表达式,还可以再简化:
- protected void Page_Load(object sender, EventArgs e)
- {
- Func<string, string> convertMeth = s => s.ToUpper();
- string name = "Dakota";
- Response.Write(convertMeth(name));
- }
protected void Page_Load(object sender, EventArgs e)
{
Func<string, string> convertMeth = s => s.ToUpper();
string name = "Dakota";
Response.Write(convertMeth(name));
}
在linq to sql中其实大量使用了Func<T, TResult>这一泛型委托,下面的例子是不是会觉得很熟悉:
- protected void Page_Load(object sender, EventArgs e)
- {
- Func<string, string> convertMeth = str => str.ToUpper();
- string[] words = { "orange", "apple", "Article", "elephant" };
- IEnumerable<String> aWords = words.Select(convertMeth);
- foreach (String s in aWords)
- {
- Response.Write(s + "<br/>");
- }
- }
protected void Page_Load(object sender, EventArgs e)
{
Func<string, string> convertMeth = str => str.ToUpper();
string[] words = { "orange", "apple", "Article", "elephant" };
IEnumerable<String> aWords = words.Select(convertMeth);
foreach (String s in aWords)
{
Response.Write(s + "<br/>");
}
}
Func<T1, T2, TResult> 委托
封装一个具有两个参数并返回 TResult 参数指定的类型值的方法。
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1,T2 arg2)
注意:Func的重载都是需要有返回值的,但是如果我的方法不需要返回值呢?那就應該是使用Action
Predicate 泛型委托
“Predicate 泛型委托”表示定义一组条件并确定指定对象是否符合这些条件的方法,其本质为一委托,在该委托中定义一组条件,用以判断传入对象是否符合这些条件,如果符合,返回True,如果不符合,返回false。
Predicate<T> 委托
表示定义一组条件并确定指定对象是否符合这些条件的方法。
public delegate bool Predicate<T>( T obj)
- T:要比较的对象的类型。
- obj:要按照由此委托表示的方法中定义的条件进行比较的对象。
- 返回值:如果 obj 符合由此委托表示的方法中定义的条件,则为 true;否则为 false。
- public class GenericDelegateDemo
- {
- List<String> listString = new List<String>()
- {
- "One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"
- };
- String[] arrayString = new String[]
- {
- "One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"
- };
- public String[] GetFirstStringFromArray()
- {
- return Array.FindAll(arrayString, (c) => { return c.Length <= 3; });
- }
- public List<String> GetFirstStringFromList()
- {
- return listString.FindAll((c) => { return c.Length <= 3; });
- }
- public String[] GetFirstStringFromArray_1()
- {
- return Array.FindAll(arrayString, GetString);
- }
- public List<String> GetFirstStringFromList_1()
- {
- return listString.FindAll(GetString);
- }
- private bool GetString(String str)
- {
- if (str.Length <= 3)
- return true;
- else
- return false;
- }
- }
public class GenericDelegateDemo
{
List<String> listString = new List<String>()
{
"One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"
};
String[] arrayString = new String[]
{
"One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"
};
public String[] GetFirstStringFromArray()
{
return Array.FindAll(arrayString, (c) => { return c.Length <= 3; });
}
public List<String> GetFirstStringFromList()
{
return listString.FindAll((c) => { return c.Length <= 3; });
}
public String[] GetFirstStringFromArray_1()
{
return Array.FindAll(arrayString, GetString);
}
public List<String> GetFirstStringFromList_1()
{
return listString.FindAll(GetString);
}
private bool GetString(String str)
{
if (str.Length <= 3)
return true;
else
return false;
}
}
(1)首先,上面以 数组和泛型List 两个集合作为演示对象,并构建集合。
(2)接着,两者同时使用各自 所有的 FindALL方法,参见如下定义:
Array : public T[] FindAll<T>(T[] array, Predicate<T> match);
List:public List<T> FindAll(Predicate<T> match);
注意的是,两处的FindAll 均采用了Predicate (泛型委托)作为参数的类型。
(3)接着,使用两者方式展现 对Predicate 的使用:
第一种: (c) => { return c.Length <= 3; };
第二种: GetString(String str)。
这两者在语法上明显不同,但是实际是做相同的事情,第一种是使用Lambda表达式构建的语句,关于Lambda这里不做详述,请参见笔者C#3.0特性相关文章。
补充的是你也可以这样写,
delegate(String c){return c.Length<=3;}
作为 Predicate定义的参数
完整代码:
XX.FindAll(delegate(String c) { return c.Length <=3; });
这应该称为匿名代理了。
其他使用到Predicate 有
Array.Find , Array.FindAll , Array.Exists , Array.FindLast , Array.FindIndex .....
List<T>.Find , List<T>.FindAll , List<T>.Exists , List<T>.FindLast , List<T>.FindIndex .....
例子二:
除了上面提到的外,你完全可以使用Predicate 定义新的方法,来加强自己代码。
- public class GenericDelegateDemo
- {
- List<String> listString = new List<String>() { "One", "Two", "Three", "Four", "Fice", "Six", "Seven", "Eight", "Nine", "Ten" };
- public String GetStringList(Predicate<String> p)
- {
- foreach (string item in listString)
- {
- if (p(item))
- return item;
- }
- return null;
- }
- public bool ExistString()
- {
- string str = GetStringList(a => { return a.Length <= 3 && a.Contains('S'); });
- if (str == null)
- return false;
- else
- return true;
- }
- }
public class GenericDelegateDemo
{
List<String> listString = new List<String>() { "One", "Two", "Three", "Four", "Fice", "Six", "Seven", "Eight", "Nine", "Ten" };
public String GetStringList(Predicate<String> p)
{
foreach (string item in listString)
{
if (p(item))
return item;
}
return null;
}
public bool ExistString()
{
string str = GetStringList(a => { return a.Length <= 3 && a.Contains('S'); });
if (str == null)
return false;
else
return true;
}
}
类型参数: TInput: 要转换的对象的类型。TOutput: 要将输入对象转换到的类型。
返回结果: TOutput,它表示已转换的 TInput。
- public delegate TOutput Converter<in TInput, out TOutput>(TInput input);
public delegate TOutput Converter<in TInput, out TOutput>(TInput input);
Converter泛型委托可以说是Func泛型委托中的一个实例
浙公网安备 33010602011771号