之前介绍过匿名方法,可以帮我们少敲很多代码,这里又有一个更好的方式可以帮我们少码更多的字,就是Lambda 表达式。
Lambda 表达式是匿名函数,它可以为委托赋值,也可以为表达式树赋值。
先介绍为委托赋值:
举个简单的例子:
过去我们是这么声明一个委托,并且执行委托中的方法的,如:
public delegate int Add(int x);
static void Main(string[] args)
{
Add add = delegate(int x)
{
return x + 15;
};
Console.WriteLine(add(5));
Console.ReadLine();
}
返回 20
上面是用匿名方法为委托赋值,现在不这样写,利用Lambda 表达式为上述委托赋值:
public delegate int Add(int x);
static void Main(string[] args)
{
Add add = x => x+15;//如果委托只有一个参数,这里的()可以省,但是0个参数或者>1个参数时,()不能省略;
Console.WriteLine(add(5));
Console.ReadLine();
}
还是返回 20
可能咋一看并不是太懂,其实主函数里的第一句话是一种省略写法,完整的写法是:
Add add = (x) => { return x + 15; };
到这里,刚接触Lambda 表达式的时候可能感觉有点奇怪,我随便写变量名(如上面的x),系统是如何知道我的变量x是什么类型的?MSDN是这么解释的:
在编写 Lambda 时,通常不必为输入参数指定类型,因为编译器可以根据 Lambda 主体、基础委托类型以及 C# 语言规范中描述的其他因素推断类型。
如果要硬写变量类型也是可以的,不过完全没必要。
如果委托有两个参数:可以这么写
public delegate int Add(int x,int y);
static void Main(string[] args)
{
Add add = (x,y) => x+y;//参数和参数之间以逗号分隔
Console.WriteLine(add(5,20));
Console.ReadLine();
}
如果委托返回的不是int型,如返回string,可以这么写:
public delegate string Add(int x, int y);
static void Main(string[] args)
{
Add add = (x, y) => (x + y).ToString();//或者Add add = (x,y) => {return (x+y).ToString();};
Console.WriteLine(add(5, 20));
Console.ReadLine();
}
上面介绍了用Lambda表达式为简单的一些委托赋值,接下来介绍类型推断提供的真正的方便。
对于类型推断的好处就是可以利用智能提示,其实在我们编码过程中,编译器就已经帮我们推断出了参数类型,:
public delegate bool CheckMovie(Movie movie);
static void Main(string[] args)
{
CheckMovie ss = a => a.Name == "少林足球";
bool result=ss(new Movie { Name = "少林足球" });
Console.WriteLine(result);
Console.ReadLine();
}
如上述代码,当我们打出a.的时候,Name属性已经自动提示出来了。因为编译器已经推断出了a的类型是Movie,这样敲代码就方便多了。其中Movie是随便自定义的一个类:
public class Movie
{
public string Name { get; set; }
public string artist { get; set; }
public string genre { get; set; }
public decimal price { get; set; }
}
返回True
或者我们要在众多电影中寻找某一部电影:
public delegate Movie SelectMovie(IEnumerable<Movie> movie);
static void Main(string[] args)
{
IEnumerable<Movie> movies = new List<Movie> {
new Movie{Name="功夫"},
new Movie{Name="晚秋"},
new Movie{Name="少林足球"}
};
//编译器自动推断出了c的类型是IEnumerable<Movie>
SelectMovie selectMovie = c =>
{
Movie mv = new Movie();
foreach (var item in c)
{
if (item.Name == "少林足球")
{
mv = item;
break;
}
}
return mv;
};
Console.WriteLine("已经找到:" + selectMovie(movies).Name);
Console.ReadLine();
}
或者我们要在众多电影中寻找某些由特定演员主演的:
public delegate IEnumerable<Movie> SelectMovie(IEnumerable<Movie> movie);
static void Main(string[] args)
{
IEnumerable<Movie> movies = new List<Movie> {
new Movie{Name="功夫",artist="周星驰"},
new Movie{Name="晚秋",artist="汤唯"},
new Movie{Name="少林足球",artist="周星驰"}
};
//编译器自动推断出了c的类型是IEnumerable<Movie>,a的类型是Movie
SelectMovie selectMovie = c => c.Where(a => a.artist == "周星驰");
IEnumerable<Movie> ms = selectMovie(movies);
foreach (var item in ms)
{
Console.WriteLine(item.artist + "----" + item.Name);
}
Console.ReadLine();
}
返回:
接下来看看Lambda 表达式中的变量范围:
public delegate bool Test();
static void Main(string[] args)
{
int t = 20;
Test td = () => {
t = 25;
return t > 21 ? true : false;
};
Console.WriteLine(t);
td();
Console.WriteLine(t);
Console.ReadLine();
}
返回:
可以看到,Lambda 表达式在为委托赋值时是没有操作外部的值类型的变量的。只有真正的执行委托中的方法后才会改变外部的值类型的变量值。
接下来试试在lambda表达式中操作引用型的外部变量:
public delegate bool Test();
static void Main(string[] args)
{
Movie mm = new Movie { Name="周星驰"};
Test td = () => {
mm.Name = "汤唯";
return mm.Name == "周星驰" ? true : false;
};
Console.WriteLine(mm.Name);
td();
Console.WriteLine(mm.Name);
Console.ReadLine();
}
可以看到,跟操作值类型的外部变量是一个效果。
综上,Lambda 表达式为委托赋值就先这么多。
接下来介绍Lambda 表达式为表达式树赋值:
public delegate bool Test(int x);
static void Main(string[] args)
{
Expression<Test> tt = a => a == 10;
Test ts = tt.Compile();
Console.WriteLine(ts(20));
Console.ReadLine();
}
上述代码,检测方法的参数是否等于10,不等于就返回False,这里返回Flase.
在日常使用中,表达式树经常跟Func<T,TResult>委托配合使用,如上述的委托可以表示成Func<int,bool>委托,不清楚Func<T,TResult>的可以看这里:
static void Main(string[] args)
{
Expression<Func<int, bool>> fc = c => c > 10;
Func<int, bool> ff = fc.Compile();
Console.WriteLine(ff(5));
Console.ReadLine();
}
上述代码判断整形参数是否大于10,这里参数值为5,返回False
关于使用Lambda表达式为委托,表达式树赋值就先记录到这里。