在委托实例化时,总要使用一个函数,所以我们去单独定义一个函数,但是在更多的时候,我们不想这样做,而是直接定义函数、直接使用,这时可以使用匿名函数或Lambda表达式,它们分别是C#2.0 和C#3.0 中引入的。
Lambda表达式
Lambda表达式(或者叫λ表达式),实际上是直接写函数头和函数体,而不写函数名,在函数头和函数体之前用符号 =>
来表示。并且将这个函数直接赋给一个委托或作为另一个函数的参数。例如:
MyDelegate d = (double x) => {
return x + 5; };
MyDelegate d = new MyDelegate((double x) => {
return x + 5; });
由于Lambda表达式总是与委托类型兼容,其类型可以由编译器来自动推断,所以可以省略参数的类型,只写参数变量的名字。例如:
MyDelegate d = (x) => {
return x + 5; };
如果只有一个参数,参数的圆括号也是可以省略的。如果只有一个返回表达式或一条语句,函数的花括号也是可以省略的。例如:
MyDelegate d = x => {
return x + 5; };
Mydelegate d = x => x + 5;
在函数的数值积分中,可以将Delegate
用Lambda表达式来书写:
result = Intergral(x => 2 * x + 1, 0, 1, 0.01);
result = Intergral(x => Math.Sin(x), 0, Math.PI, 0.01);
可以说,Lambda表达式就是一个内嵌函数,更准确地说是一个内嵌的委托变量。
匿名函数
匿名函数就是没有名字的函数,在定义函数的同时如果马上赋值给委托,所以不需要名字,或者说由编译器来自动生成名字。为了表示它是一个匿名函数,前面要加一个关键字delegate
。例如:
MyDelegate d = delegate (double x){
return x + 5; };
这里需要注意的是:delegate
在这里表示匿名函数,虽然delegate
这个词也可以用来定义委托类型,但编译器是不会混淆的。
可见,匿名函数与Lambda表达式是差不多的,只不过匿名函数使用delegate来表示,而Lambda表达式使用 =>
来表示。由于Lambda可以省略的更多,所以现在很少用匿名函数了。
如果说匿名函数有一个用途的话,那就是匿名函数不用写参数类型及参数名,如:
MyDelegate d = delegate {
return 100; };
不过,用Lambda表达式也并不麻烦:
MyDelegate d = x => 100;
属性、索引器的简写
Lambda表达式(以及匿名函数)不仅可以简化函数调用时的参数的书写,在C#6.0 以上版本中,还可以简化方法、属性、索引器等成员的定义,称为“表达式体成员”(expression bodied members)。例如:
public double Square(double n) => n * n; // 方法
public double Dist => Math.Sqrt(X * X + Y * Y); // 只读属性
public int this[int a] => members[a]; // 只读索引器
第1句和第2句分别定义了属性和方法(只有get
,没有set
)。
在C#7.0 以上版本中,还可以在构造方法、set属性等更多的运用“表达式体成员”,如:
public Person(string name) => names.TryAdd(id, name);
public string Name{
get => names[id]; // getters
set => names[id] = value; // setters
}
3个示例程序:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
class Program
{
static void Main(string[] args) {
Console.WriteLine("Hello World!");
Example2();
Console.WriteLine("---------------------分割线---------------------");
Example3();
}
// 示例1, 使用线程
private void Example1() {
// csharp 1.0
// 使用委托,使用已定义好的函数
new Thread(new ThreadStart(MyFun)).Start();
// csharp 2.0
// 省略委托:MyFun自动实例化为ThreadStart委托
new Thread(MyFun).Start();
// 匿名方法
new Thread(new ThreadStart(delegate () {
Console.WriteLine("my function"); })).Start();
// 匿名方法, 省略参数列表
new Thread(new ThreadStart(delegate {
Console.WriteLine("my function"); })).Start();
// 匿名方法, 自动转委托
new Thread(delegate () {
Console.WriteLine("my function"); }).Start();
// csharp 3.0
// Lambda表达式
new Thread(() => {
Console.WriteLine("my function"); }).Start();
}
private void MyFun() {
Console.WriteLine("my function");
}
// 示例2, 使用事件
public class TestEventArgs
{
// 事件数据
public string name;
public TestEventArgs(string name) {
this.name = name; }
}
public delegate void TestHandler(object sender, TestEventArgs e); // 1.声明委托, 公用的
public class TestEvent
{
public event TestHandler Test; // 2.声明事件, 在一个类中
public void UseTestEvent() {
Test(this, new TestEventArgs("name")); } // 调用事件Test
}
private static void Example2() {
TestEvent testEvent = new TestEvent();
// csharp 1.0
// 使用委托, 使用自定义函数
testEvent.Test += new TestHandler(TestEvent_Test); // 3.在别的类中注册事件
// csharp 2.0
// 自动转委托
testEvent.Test += TestEvent_Test;
// 匿名方法
testEvent.Test += new TestHandler(delegate (object sender, TestEventArgs e) {
Console.WriteLine("TestEvent_Test " + e.name); });
// 匿名方法, 自动转委托
testEvent.Test += delegate (object sender, TestEventArgs e) {
Console.WriteLine("TestEvent_Test " + e.name); };
// csharp 3.0
// 使用Lambda表达式
testEvent.Test += (object sender, TestEventArgs e) => {
Console.WriteLine("TestEvent_Test " + e.name); };
testEvent.Test += (sender, e) => {
Console.WriteLine("TestEvent_Test " + e.name); };
testEvent.UseTestEvent();
}
private static void TestEvent_Test(object sender, TestEventArgs e) {
Console.WriteLine("TestEvent_Test " + e.name);
}
// 示例3, 数组排序
class Book
{
public string title;
public double price;
public Book(string title, double price) {
this.title = title; this.price = price; }
}
private static void Example3() {
Random rnd = new Random();
Book[] books = new Book[10];
for (int i = 0; i < books.Length; i++) books[i] = new Book("Book" + i, rnd.Next(100));
foreach (Book book in books) Console.WriteLine(book.title + " " + book.price);
Console.WriteLine();
// csharp 1.0
Array.Sort(books, new MyComparer());
// csharp 2.0
// 使用Comparison委托
Array.Sort<Book>(books, new Comparison<Book>(delegate (Book book1, Book book2) {
return (int)(book1.price - book2.price); }));
Array.Sort<Book>(books, delegate (Book book1, Book book2) {
return (int)(book1.price - book2.price); });
// csharp 3.0
Array.Sort<Book>(books, (Book book1, Book book2) => (int)(book1.price - book2.price));
Array.Sort<Book>(books, (book1, book2) => (int)(book1.price - book2.price)); //省略参数类型
foreach (Book book in books) Console.WriteLine(book.title + " " + book.price);
// 使用Linq
IOrderedEnumerable<Book> result = from book in books orderby book.price select book;
var result1 = from book in books where book.price >= 0 orderby book.price select book.title;
foreach (string s in result1) Console.WriteLine(s);
var result2 = books
.Where<Book>(b => b.price >= 0)
.OrderBy<Book, double>(b => b.price, Comparer<double>.Default)
.Select<Book, Book>(book => book);
foreach (Book b in result2) Console.WriteLine(b.price + " ");
}
class MyComparer : System.Collections.IComparer
{
public int Compare(object x, object y) {
return (int)(((Book)x).price - ((Book)y).price);
}
}
}