匿名方法与Lambda表达式
1.匿名方法
在学习委托时,我们知道委托实例至少要绑定一个方法才能使用,而调用委托实际上是调用了它所关联地方法。一般来说,需要定义一个与委托签名相符的方法,并使之与委托变量关联。如以下代码:
Action deleg=new Action(CallMethod);//声明并实例化委托变量
private static void CallMethod()//与委托关联的方法
{.........}
会发现以上写法并不简洁,因此引入了“匿名方法”,它不需要命名,用一个delegate关键字代表方法的名字,没有访问修饰符,也不需要返回类型。
例如上面的例子可以简写如下:
Action deleg=delegate()
{........};
当委托既有参数又有返回值的时候,匿名方法中就也要相应定义参数,如果委托的签名中有返回值,则在匿名方法中就直接使用return返回即可,如下实例:
Func<int,int,int> f=delegate(int x,int y)
{ return x+y;};
int result=f(1+2);//调用委托
其实上例所用的委托的原型如下:delegate TResult Func<in T1,in T2,out TResult>(T1 x,T2 y);
如果委托要关联地方法在代码中没有重复使用,使用匿名方法会非常方便,当方法在代码中多个地方都用到,就不应该在使用匿名方法。
2.Lambda表达式
Lambda表达式其实就是更为简洁的匿名方法表示法,以“=>”作为分隔符,其左边为匿名方法的参数列表,右边为匿名方法的语句,即:(参数列表)=><语句>
对于没有参数的委托,Lambda表达式如下:()=><语句>
2.1 Lambda表达式用于给委托变量赋值
(1)对于没有参数,返回值为void类型的委托
Action a=()=>{/*........*/};
如果“=>”右边只有一句代码,则可以省略大括号,写出:Action a=()=>Console.WriteLine("");
(2)对于有参数的委托
Action<string,int> a=(string name,int age)=>Console.WriteLine("");
由于Lambda表达式可以根据委托来识别参数类型,所以可以省略(string name,int age)中的参数类型。
(3)对于有返回值的委托(非void类型),则直接用return 返回即可。
Func<int,int ,int> a=(a,b)=>{return a*b;};
如果“=>”后边只有一句代码,可以吧return和大括号省略,如下所示:
Func<double, string> a=(n)=>n.ToString("C2");
2.2 Lambda表达式用于参数传递
比如.NET类库的许多扩展方法以及LINQ表达式都可以使用Lambda表达式传递参数。示例代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Test { #region 定义类型 public class Student { public string Name { get; set; } public int Age { get; set; } public DateTime Date { get; set; } } #endregion class Program { static void Main(string[] args) { List<Student> stus = new List<Student>(); stus.Add(new Student { Name = "小王", Age = 22, Date = new DateTime(2012, 9, 22) }); stus.Add(new Student { Name = "小刘", Age = 23, Date = new DateTime(2013, 1, 10) }); stus.Add(new Student { Name = "小红", Age = 21, Date = new DateTime(2012, 3, 2) }); // 将学员的入学日期按升序排序 var res = stus.OrderBy(stu => stu.Date); Console.WriteLine("学员的入学日期按升序排序:"); foreach (Student s in res) { Console.WriteLine("姓名:{0},年龄:{1},入学日期:{2:yyyy-M-d}", s.Name, s.Age, s.Date); } Console.ReadKey(); } } }
以上代码使用了OrderBy扩展方法的以下重载:
public static IOrderedEnumerble<TSource> OrderBy<TSource,TKey>(this IEnumerble<TSource> source,Func<TSource,TKey> keySelector);
在调用时,主要关注keySelector参数,因为第一个参数是要扩展的类型,由编译器调用。keySelector参数是Func<TSource,TKey>,输入类型为TSource,TKey是要返回的值,OrderBy方法将根据TKey来进行排序。实例中,stu会自动识别为Student类型,“=>”右边直接将stu的Date属性值返回,OrderBy方法通过调用传递给keySelector参数的委托来获取每个Student实例的Date属性值,以便进行排序。