Lambda

简介

Lambda 表达式是一种可用于创建委托表达式目录树类型的一种匿名函数(匿名方法+Lambda)。通过使用 lambda 表达式,可以写入可作为参数传递或作为函数

调用值返回的本地函数。Lambda 表达式对于编写 LINQ 查询表达式特别有用,使用可以减少代码量(eg:分组、字典转化中),提高可读性(eg:用在递进式Linq中)。

Lambda 表达式语法:(左侧指定输入参数,注:括号在只有一个参数下才是可选的)=> 右侧输入表达式或语句块。

应用

定义一个动物实体类AnimalModel,预存储一些动物数据。

 /// <summary>
/// 动物实体
/// </summary>
public class AnimalModel
{
/// <summary>
/// 名称
/// </summary>
public string Name { set; get; } /// <summary>
/// 重量
/// </summary>
public decimal Weight { set; get; } /// <summary>
/// 是否是鸟类
/// </summary>
public bool isBird { set; get; } /// <summary>
/// 寿命
/// </summary>
public decimal Lifetime { set; get; }
}
 List<AnimalModel> animalInfo = new List<AnimalModel>();

         public Form1()
{
InitializeComponent();
Lambda la = new Lambda();
animalInfo = la.LoadAllAnimal();
string allAnimals = string.Empty;
foreach (var item in animalInfo)
{
allAnimals += string.Format("名称:{0}, 重量:{1}, 是否是鸟类:{2}, 寿命:{3}\r\n",
item.Name,
item.Weight,
(item.isBird ? "是" : "否"),
item.Lifetime);
}
txt_reveal.Text = allAnimals;
}

显示结果如图:

linq中应用

Lambda可以取代匿名方法,除了一种情况:匿名方法提供了Lambda表达式中所没有的功能。匿名方法可用来忽略参数列表,可转换为具有各种签名的委托。

但在Linq中的应用中,Lambda相对于匿名委托有着绝对的优势。至于Lambda的性能问题,我个人觉得影响不大,只要代码中少出现类似“重复计算”或“.Count()>0判空

这种代码,性能影响是可接受的。

用匿名委托和Lambda表达式分别实现一个筛选逻辑。可以看到Lambda明显比匿名方式更加简洁,更加人性化。在一个条件查询中都会看出差距,如果是涉及到

较复杂的筛选逻辑,Lambda的简洁和可读性优势更明显。

/// <summary>
/// Lambda
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_lambda_Click(object sender, EventArgs e)
{
string animalName = txt_animal.Text; var seaAnimal = animalInfo.Where(p => p.Name.Contains(animalName)).ToList(); string allAnimals = string.Empty;
foreach (var item in seaAnimal)
{
allAnimals += string.Format("名称:{0}, 重量:{1}, 是否是鸟类:{2}, 寿命:{3}\r\n",
item.Name,
item.Weight,
(item.isBird ? "是" : "否"),
item.Lifetime);
} txt_reveal.Text += "Lambda查询结果:\r\n" + allAnimals;
}
      /// <summary>
/// 匿名
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_anonymity_Click(object sender, EventArgs e)
{ #region 匿名筛选动物 string animalName = txt_animal.Text; //分配内存块+执行
List<AnimalModel> seaAnimal = animalInfo.Where(
delegate(AnimalModel p)
{
return p.Name.Contains(animalName);
})
.ToList(); //只有在调用匿名方法委托实例的时候才会执行匿名方法内部的操作
//单纯的创建委托实例并不会立即执行匿名方法代码块。
string allAnimals = string.Empty;
foreach (var item in seaAnimal)
{
allAnimals += string.Format("名称:{0}, 重量:{1}, 是否是鸟类:{2}, 寿命:{3}\r\n",
item.Name,
item.Weight,
(item.isBird ? "是" : "否"),
item.Lifetime);
}
txt_reveal.Text += "匿名查询结果:\r\n" + allAnimals; #endregion //需要分组 且 转换成 Dictionary的情况,用匿名就复杂多了
var animalDic = animalInfo.GroupBy(delegate (AnimalModel p) { return p.Lifetime; })
.ToDictionary(
delegate (IGrouping<decimal, AnimalModel> g) { return g.Key; },
delegate (IGrouping<decimal, AnimalModel> g)
{
return g.OrderBy(delegate (AnimalModel s) { return s; }).ToList();
}); }

表达式树中应用

表达式树也称表达式目录树,将代码以一种抽象的方式表示成一个对象树,树中每个节点本身都是一个表达式。表达式树不是可执行代码,它是一种数据结构

由4部分组成:Body 主体部分,Parameters 参数部分,NodeType 节点类型,Lambda表达式类型,是Linq(lambda+表达式树+扩展方法)的核心。

语法:Expression<Func<type,returnType>> = (param) => lamdaexpresion;

表达式树用途:

1、用在动态编码中,效率比反射要高许多。但是Compile调用过程涉及动态代码生成,最好只调用一次,或者直接使用静态编码

2、在LINQ to SQL中使用,我们需要将LINQ to SQL查询表达式(返回IQueryable类型)转换成表达式树。之所以需要转换是因为LINQ to SQL查询表达式

不是在C#代码中执行的,LINQ to SQL查询表达式被转换成SQL,通过网络发送,最后在数据库服务器上执行。

现在来创建一个Lambda一个计算(w+y)*(x+y)的表达式树。

 //创建一个表达式树中的参数,作为一个节点,这里是最下层的节点
ParameterExpression w = Expression.Parameter(typeof(int), "w");
ParameterExpression x = Expression.Parameter(typeof(int), "x"); //这里w+y,生成表达式树中的一个节点,比上面节点高一级
BinaryExpression wx = Expression.Add(w, x); //创建一个表达式树中的参数,作为一个节点,这里是最下层的节点
ParameterExpression y = Expression.Parameter(typeof(int), "y");
ParameterExpression z = Expression.Parameter(typeof(int), "z"); //这里y+z,生成表达式树中的一个节点,比上面节点高一级
BinaryExpression yz = Expression.Add(y, z); //运算两个中级节点,产生终结点
BinaryExpression result1 = Expression.Multiply(wx, yz); Expression<Func<int, int, int, int, int>> lambda = Expression.Lambda<Func<int, int, int, int, int>>(result1, w, x, y, z); //将表达式树描述的lambda表达式,编译为可执行代码,并生成该lambda表达式的委托;
Func<int, int, int, int, int> fa = lambda.Compile(); txt_reveal.Text += fa(, , , ) + "\r\n"; //输出结果

编译器处理方式

Lambda的定义就是:既可以用于创建委托,又可以用于创建表达式树的匿名函数。但是编译器对Lambda的处理逻辑又是怎么的?是生成可执行委托实例,还是

生成表达式树。取决于Lambda赋予的类型。当Lambda赋予委托变量时,编译器自动生成可执行委托实例;当Lambda赋予Expression变量时,编译器自动生成表达

式树。

委托

简介

委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。是一种安全地封装方法的类型,它与 C 和C++ 中的函数指针类似。

与 C 中的函数指针不同,委托是面向对象的、类型安全的和保险的体现在对于函数指针所引用的函数指令块的类型检测,比如返回值,参数类型,参数个数)。

委托的类型由委托的名称定义。

委托一般都是滞后调用,编写委托实现的人一般不知道具体何时该方法被调用。.net的委托是类且具有内建(内存机制)支持,可进行异步和广播式的调用。委托跟事件可自然的契合,

一般是事件激发导致委托被调用。.net中委托既可指向实例方法也可指向静态方法。

       对于委托还比较陌生,想更深入研究的同学。建议先从Lambda开始学习(工作中大部分同学接触Lambda比delegate更多,更早),再层层向内部,

反向学习匿名函数、委托。

Delegate

delegate是我们接触最早,最常用的一种委托。也是最灵活的一种委托,支持参数个数最多可达32个,即可支持有返回值,也支持无返回值。

操作分三步:定义委托(生成指针,放入堆);将实例化对象和委托绑定 (委托指针与实例化对象内存地址关联上);执行委托。

例子:

 /// <summary>
/// 声明委托
/// </summary>
/// <param name="firstStr">第一个夫字符串</param>
/// <param name="secondStr">第二个字符串</param>
/// <returns></returns>
public delegate string OprateString(string firstStr, string secondStr); /// <summary>
/// Delegate
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_delegate_Click(object sender, EventArgs e)
{
DelegateOpt ctStr = new DelegateOpt(); //指针连接对象地址
OprateString pttStr = ctStr.ConnectString; //同步直接执行委托
string result= pttStr.Invoke("同学:", "学习委托delegate"); //取消绑定,再重新绑定
pttStr-= ctStr.ConnectString;
pttStr += ctStr.ExcludeString;
//指针连接对象地址
IAsyncResult iAsyncRsl = pttStr.BeginInvoke("同学:", "学习委托delegate", null,null);
//主线程中........可在此段时间做其他的事
//Thread.Sleep(1000);//主线程休息2秒钟
string returnStrFromAsyncMethod = pttStr.EndInvoke(iAsyncRsl);//调用EndInvoke返回最终结果 txt_reveal.Text = returnStrFromAsyncMethod + "\r\n"; //输出结果
} /// <summary>
/// 连接字符串
/// </summary>
/// <param name="firstStr"></param>
/// <param name="secondStr"></param>
/// <returns></returns>
public string ConnectString(string firstStr, string secondStr)
{
return firstStr + secondStr;
} /// <summary>
/// firstStr 中排除 secondStr
/// </summary>
/// <param name="firstStr"></param>
/// <param name="secondStr"></param>
/// <returns></returns>
public string ExcludeString(string firstStr, string secondStr)
{
return firstStr.IndexOf(secondStr) > - ? firstStr.Replace(secondStr, "") : firstStr;
}

Action中用Lambda

Action<T1,... ,Tx>  当今比较常见的一种委托 ,以参数形式传递方法,而不用显式声明自定义的委托。 封装的方法必须与此委托定义的方法签名相对应,不能有返回值(在 C# 中,该方法必

须返回 void)。相对于delegate,少了定义委托步骤,至少1个参数,至多4个参数,无返回值。

例子:

        /// <summary>
/// 同步获取队列消息
/// </summary>
/// <typeparam name="T">返回的数据类型</typeparam>
/// <param name="action">获取数据后的回调</param>
public void Receive<T>(Action<T> action) where T : class
{
try
{
mqueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
Message message = mqueue.Receive();
T obj = message.Body as T;
if (obj != null)
action(obj);
else
throw new InvalidCastException("队列获取的类型与泛型类型不符");
}
catch (Exception ex)
{
throw ex;
}
}
 /// <summary>
/// 接收消息
/// </summary>
/// <param name="queueName">队列</param>
/// <param name="isAsy">是否异步</param>
public user ReceiveMessage(string queueName, bool isAsy)
{
user userInfo = new user();
MessageQueueSettings mqs = new MessageQueueSettings()
{
MessageQueueName = queueName
};
IMessageQueueBase messageQueueBase = new MessageQueueBase(mqs);
if (!isAsy)
{ ///直接用lambda 获取接收信息
messageQueueBase.Receive<user>(p =>
{
userInfo = p;
});
}
else
{
messageQueueBase.ReceiveAsync<user>(p =>
{
userInfo = p;
});
}
return userInfo;
}

Func中用Lambda

用法类似的最流行的一种委托,相对于Action多了一个可以返回信息功能,至少0个参数,至多4个参数,根据返回值泛型返回。

例子:与Expression一起使用,直接操作lambda.

        /// <summary>
/// 根据表达式查询数据
/// </summary>
/// <typeparam name="T">查询的数据类型</typeparam>
/// <param name="express">表达式</param>
/// <returns>查询结果</returns>
public IList<T> FindDataByExpress(Expression<Func<T, bool>> express)
{
try
{
return collection.AsQueryable().Where(express).ToList<T>();
}
catch (Exception ex)
{
throw ex;
}
}
        /// <summary>
/// 列表查询测试
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public IList<users> TestSearchList(users user)
{
string dbName = MongoDatabase.LW_Test.GetEnumItemDescription();
var mongoBase = new MongoBase<users>(dbName).GetDBHelper();
var result = mongoBase.FindDataByExpress(p => p.Age == user.Age && p.Name.Contains(user.Name));
return result;
}

应用的场景

1、一般在多个功能对一个功能依赖的一对多关系中用到,当一个对象改变时,其他依赖它的对象随之发生相应改变。

2、实体操作类中用到,现在操作数据库的持久化处理程序,多数是直接数据实体映射,用Action和Func处理很方便。

3、待补充。。。

lambda和委托那点事的更多相关文章

  1. lambda和委托

    Lambda 简介 Lambda 表达式是一种可用于创建委托或表达式目录树类型的一种匿名函数(匿名方法+Lambda).通过使用 lambda 表达式,可以写入可作为参数传递或作为函数 调用值返回的本 ...

  2. C#利用lambda实现委托事件的挂接

    转自:http://www.cdtarena.com/cpx/201307/9287.html在写一个小程序的时候,碰到了这样的问题,需要用委托来挂接事件,但是又想在这事件中使用局部的变量,而委托一旦 ...

  3. LINQ、Lambda与委托

    首先定义个Person类: public class Person { public string Name{get;set;} //姓名 public int Age{get;set;} //年龄 ...

  4. Lambda与委托

    Lambda 表达式是一个可用于创建委托或表达式树类型的匿名函数. 通过使用 lambda 表达式,可以可作为参数 或 返回为函数调用值的本地函数.Lambda 表达式对于编写 LINQ 查询表达式特 ...

  5. 关于javaScript事件委托的那些事

    今天是第一次写稿,还是有那么一丢丢小鸡冻...回归正题啦... 关于javaScript事件委托不得不说的那些事,为什么要使用事件委托? 我们可以这么说,假设老板要分配一项任务,首先要秘书叫A君来到办 ...

  6. C#中匿名函数、委托delegate和Action、Func、Expression、还有Lambda的关系和区别

    以前一直迷迷糊糊的,现在总算搞明白. Lambda表达式 Lamda表达式基本写法是()=>{ };Lambda和方法一样都可以传入参数和拥有返回值.(int x)=>{return x; ...

  7. C# 委托 (一)—— 委托、 泛型委托与Lambda表达式

    C# 委托 (一)—— 委托. 泛型委托与Lambda表达式 2018年08月19日 20:46:47 wnvalentin 阅读数 2992   版权声明:此文乃博主之原创.鄙人才疏,望大侠斧正.此 ...

  8. 基础知识---委托和 lambda

    委托定义类型,类型指定特定方法签名. 可将满足此签名的方法(静态或实例)分配给该类型的变量,然后(使用适当参数)直接调用该方法,或将其作为参数本身传递给另一方法再进行调用. 以下示例演示了委托的用法. ...

  9. c++11 lambda(了解)

    this->send_change_equip = ([this](ChangeEquipPT channge) { send_cmd(s2c_change_equip, &channg ...

随机推荐

  1. 启动myeclipse弹窗Please allow Subclipse team to receive anonymous usage statistics for this Eclipse intance

    Please allow Subclipse team to receive anonymous usage statistics for this Eclipse intance(翻译:请允许Sub ...

  2. Bitmap.createBitmap函数有6个重载方法

    位图剪切参考重载方法4和6,重载方法6比较简单 public static Bitmap createBitmap (Bitmap src)从原位图src复制出一个新的位图,和原始位图相同 publi ...

  3. live555简介

    live555 编辑   目录 1live555简介 2Live555 Streaming Media整体框架 3openRTSP客户端流程     1live555简介编辑 Live555 是一个为 ...

  4. 2019浙师大校赛(浙大命题)(upc复现赛)总结

    2019浙师大校赛(浙大命题)(upc复现赛)总结 早上九点开始.起得迟了,吃了早饭慌慌张张跑过去,刚到比赛就开始了. 开始分别从前往后和从后往前看题,一开始A题,第一发WA,第二次读题发现漏看了还有 ...

  5. BZOJ 1565 植物大战僵尸 最大权闭合子图+网络流

    题意: 植物大战僵尸,一个n*m的格子,每 个格子里有一个植物,每个植物有两个属性: (1)价值: (2)保护集合,也就是这个植物可以保护矩阵中的某些格子. 现在你是僵尸,你每次只能从(i,m) 格子 ...

  6. 零基础入门学习Python(14)--字符串:各种奇葩的内置方法

    前言 这节课我们回过头来,再谈一下字符串,或许我们现在再来谈字符串,有些朋友可能觉得没必要了,甚至有些朋友就会觉得,不就是字符串吗,哥闭着眼也能写出来,那其实关于字符串还有很多你不知道的秘密哦.由于字 ...

  7. Python之机器学习-朴素贝叶斯(垃圾邮件分类)

    目录 朴素贝叶斯(垃圾邮件分类) 邮箱训练集下载地址 模块导入 文本预处理 遍历邮件 训练模型 测试模型 朴素贝叶斯(垃圾邮件分类) 邮箱训练集下载地址 邮箱训练集可以加我微信:nickchen121 ...

  8. C++迭代器之'插入迭代器

    1. 定义 插入型迭代器(Insert Iterator),又叫插入器(Inserter). 2. 作用 插入迭代器的主要功能为把一个赋值操作转换为把相应的值插入容器的操作.算法库对所有在容器上的操作 ...

  9. HDU-1083Courses,二分图模板题!

    Courses                                                                                             ...

  10. 防火墙内设置FileZilla Server注意事项

    开启了Windows下的防火墙,如何设置FileZilla Server 相关选项,能在服务器端只开启21,23端口就可以正常连接使用 方法/步骤   1.       开启windows防火墙,同时 ...