基础知识:labda表达式其实就是对匿名方法的封装(或者说简写)。()里面代表方法的参数。
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();
}
}
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); //s 代表是一个参数,并且是string类型的
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);
}
}
泛型委托与直接显示声明自定义委托的示例比较:
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);
}
}
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);
}
}
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);
}
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方法
}
这段代码很容易理解,定义一个方法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));
}
运行后,与前一种写法结果完全相同,这里再联系官方解释想一想,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));
}
怎么样?是不是清爽很多了,但这并不是最简洁的写法,如果利用Lambda表达式,还可以再简化:
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/>");
}
}
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;
}
}
(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 .....
例子二:在自定义对象中的应用:
StandardBudgetAccountsMDL为一个实体类。(匿名委托在.net 2.0中开始出现)
List<StandardBudgetAccountsMDL> sbaFormularList ;
List<StandardBudgetAccountsMDL> SBAList;
if (rblBudgetType.SelectedValue == "YY")
{
SBAList = BudgetManagementBFL.GetStandardBudgetAccounts1(ParamCycleId, YYBudgetTypeId, EnumValueState.Confirmed);
//在上述列表的基础上,返回CalculatedProperty 等于某一个值的List集合
sbaFormularList = SBAList.FindAll(delegate(StandardBudgetAccountsMDL o) { return o.CalculatedProperty == "95752c4a-dc81-40f6-8854-fd8be94990a6"; });
}
例子三:
除了上面提到的外,你完全可以使用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;
}
}
类型参数: TInput: 要转换的对象的类型。TOutput: 要将输入对象转换到的类型。
返回结果: TOutput,它表示已转换的 TInput。
public delegate TOutput Converter<in TInput, out TOutput>(TInput input);
Converter泛型委托可以说是Func泛型委托中的一个实例