C#语法之匿名函数和Lambda表达式

时间:2022-05-11 20:06:54

上一篇博客主要是对委托和事件做了一小结,这篇是在上一篇博客的基础上对匿名函数和Lambda表达式小结。还是接着上一篇说起,在上一篇中也说了委托是一种数据结构,主要是解决让函数作为参数的问题。在使用委托时首先要声明代理,然后实例化,并将委托对象和已定义好的函数关联上,最后调用。这里与已定义好的函数关联的事情,如果函数是经常使用的也还好,如果不是经常使用的可能只调用一次,那这岂不是老费劲了。就是能不能在使用的时候定义下呢?于是乎有了匿名方法。

一、匿名方法的使用。

匿名方法的使用步骤和委托的使用步骤相同,只是实例化的格式不同。匿名方法的格式:

委托名 实例变量 =delegate(形参列表)

{

};

1.形参列表:参数列表应该和委托声明的匹配。若无可用()表示

2.返回值:返回值也是需要和委托类型的返回值匹配。

二、demo

和委托事件的例子一样,还是定义了一个Person类,并声明了委托EatFoodDelegate。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegate
{
//定义了一个从System.Delegate类派生的类
//也可以理解为一种数据类型 这种数据类型指向返回值为void 参数为Person对象的函数
//我们也可以把Person类理解为一种数据类型 只是它包含的是Name和Age
public delegate void EatFoodDelegate(Person p);

public class Person
{

public string Name { get; set; }

public int Age { get; set; }

public Person(string name, int age)
{
Name
= name;
Age
= age;
}

//既然委托是一数据类型和String一样,所以可以像声明String对象一样声明代理变量
public EatFoodDelegate eatFoodDelegate;
////之前是直接声明委托,现在是声明一个事件
//public event EatFoodDelegate EatFoodEventHandler;

public void eating()
{

if (eatFoodDelegate != null)
{
eatFoodDelegate(
this);
}
}

}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegate
{
class Program
{
static void Main(string[] args)
{
Person chinesePerson
= new Person("小明",25);
//通过构造函数实例化对象
chinesePerson.eatFoodDelegate += new EatFoodDelegate(chineseEat);
chinesePerson.eating();

Console.WriteLine(
"--------------------------------------");


EatFoodDelegate EnglishEatPisaDelegate
= delegate (Person p)
{
Console.WriteLine(
"I'm {0},I am {1} , I eat PiSa", p.Name, p.Age);
};

Person englishPerson
= new Person("Ivan",25);
englishPerson.eatFoodDelegate
= delegate (Person p)
{
Console.WriteLine(
"I'm {0},I am {1} , I eat MianBao", p.Name, p.Age);
};
englishPerson.eatFoodDelegate
+= EnglishEatPisaDelegate;
englishPerson.eating();
Console.ReadLine();
}
static void chineseEat(Person p)
{
Console.WriteLine(
"我是{0},我今年{1}岁了,我吃馒头",p.Name,p.Age);
}

}

}

在上面代码中可以看到,实例化了两个Person对象,chinesePerson、englishPerson。如果按照上一博客委托的形式还是要new 一个委托对象,将委托和已定义好的函数关联起来。ps:注意委托调用和函数的位置关系。

我们使用匿名方法的方式实现了上一篇博客委托中要实现的功能。只是在englishPerson对象指定委托变量之前先声明了一个匿名方法,这个函数的声明周期也是很短的,然后又声明了一个匿名方法直接赋值给englishPerson的委托。

从上面的两个对象使用委托的比较,我们也可以看出匿名函数的好处。

1.代码结构方面

按照上一博客的方法,委托对象关联已有的方法,这个在代码结构上委托对象和方法是分离的,这个*是代码位置的分离,实例化委托对象可能会在一个方法里面,而关联的方法会是另一个方法,虽然都是在一个类中,但在方法比较多的类中,影响代码检视,查看的时候还要跳转。而在匿名方法中,在调用的时候才会实例化,这样委托方法和调用离得就很近,很容易查看。

2.声明周期

对于一定义的方法,它是定义在类中,而匿名方法则是定义在调用的方法中,声明周期短。对于不经常调用,可能只在这一个地方使用的关联方法,没有必要定义在类中。

三、Lamdba表达式

对于上面的匿名方法还有一个好处就是简洁方便,也主要是帮助有懒癌的小伙伴们,那可能有懒癌到晚期的会问还有没有更简洁方便的能多简洁就多简洁,于是乎Lamdba表达式出现了,它也是匿名方法。下面是它的格式:

(参数列表)=>表达式或语句块

Lambda运算符:所有的lambda表达式都是用新的lambda运算符 " => ",可以叫他,“转到”或者 “成为”。运算符将表达式分为两部分,左边指定输入参数,右边是lambda的主体。还是使用同一个例子稍微改动下代码来说明下Lamdba表达式。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegate
{
class Program
{
static void Main(string[] args)
{
Person chinesePerson
= new Person("小明",25);
//通过构造函数实例化对象
chinesePerson.eatFoodDelegate += new EatFoodDelegate(chineseEat);
chinesePerson.eating();

Console.WriteLine(
"--------------------------------------");

Person englishPerson
= new Person("Ivan",25);
englishPerson.eatFoodDelegate
= (Person p) => {
Console.WriteLine(
"I'm {0},I am {1} , I eat MianBao", p.Name, p.Age);
};
englishPerson.eatFoodDelegate
+= (Person p) => {
Console.WriteLine(
"I'm {0},I am {1} , I eat PiSa", p.Name, p.Age);
};
englishPerson.eating();
Console.ReadLine();
}
static void chineseEat(Person p)
{
Console.WriteLine(
"我是{0},我今年{1}岁了,我吃馒头",p.Name,p.Age);
}
}
}

定义Person类就不贴了,上面主要是在englishPerson对象上,上面指定eatFoodDelegate委托的函数是使用Lamdba实现的。可以看到左边是(Person p),右边是代码,中间是Lamdba运算符=>.用上面的与匿名方法的那个demo做比较发现这种方式更为简洁方便。不用再使用delegate关键字创建匿名方法了。

对于泛型委托,就放在泛型部分来了解吧。