Lambda

简介

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

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

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

应用

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

  1. /// <summary>
  2. /// 动物实体
  3. /// </summary>
  4. public class AnimalModel
  5. {
  6. /// <summary>
  7. /// 名称
  8. /// </summary>
  9. public string Name { set; get; }
  10.  
  11. /// <summary>
  12. /// 重量
  13. /// </summary>
  14. public decimal Weight { set; get; }
  15.  
  16. /// <summary>
  17. /// 是否是鸟类
  18. /// </summary>
  19. public bool isBird { set; get; }
  20.  
  21. /// <summary>
  22. /// 寿命
  23. /// </summary>
  24. public decimal Lifetime { set; get; }
  25. }
  1. List<AnimalModel> animalInfo = new List<AnimalModel>();
  2.  
  3. public Form1()
  4. {
  5. InitializeComponent();
  6. Lambda la = new Lambda();
  7. animalInfo = la.LoadAllAnimal();
  8. string allAnimals = string.Empty;
  9. foreach (var item in animalInfo)
  10. {
  11. allAnimals += string.Format("名称:{0}, 重量:{1}, 是否是鸟类:{2}, 寿命:{3}\r\n",
  12. item.Name,
  13. item.Weight,
  14. (item.isBird ? "是" : "否"),
  15. item.Lifetime);
  16. }
  17. txt_reveal.Text = allAnimals;
  18. }

显示结果如图:

linq中应用

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

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

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

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

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

  1. /// <summary>
  2. /// Lambda
  3. /// </summary>
  4. /// <param name="sender"></param>
  5. /// <param name="e"></param>
  6. private void btn_lambda_Click(object sender, EventArgs e)
  7. {
  8. string animalName = txt_animal.Text;
  9.  
  10. var seaAnimal = animalInfo.Where(p => p.Name.Contains(animalName)).ToList();
  11.  
  12. string allAnimals = string.Empty;
  13. foreach (var item in seaAnimal)
  14. {
  15. allAnimals += string.Format("名称:{0}, 重量:{1}, 是否是鸟类:{2}, 寿命:{3}\r\n",
  16. item.Name,
  17. item.Weight,
  18. (item.isBird ? "是" : "否"),
  19. item.Lifetime);
  20. }
  21.  
  22. txt_reveal.Text += "Lambda查询结果:\r\n" + allAnimals;
  23. }
  1. /// <summary>
  2. /// 匿名
  3. /// </summary>
  4. /// <param name="sender"></param>
  5. /// <param name="e"></param>
  6. private void btn_anonymity_Click(object sender, EventArgs e)
  7. {
  8.  
  9. #region 匿名筛选动物
  10.  
  11. string animalName = txt_animal.Text;
  12.  
  13. //分配内存块+执行
  14. List<AnimalModel> seaAnimal = animalInfo.Where(
  15. delegate(AnimalModel p)
  16. {
  17. return p.Name.Contains(animalName);
  18. })
  19. .ToList();
  20.  
  21. //只有在调用匿名方法委托实例的时候才会执行匿名方法内部的操作
  22. //单纯的创建委托实例并不会立即执行匿名方法代码块。
  23. string allAnimals = string.Empty;
  24. foreach (var item in seaAnimal)
  25. {
  26. allAnimals += string.Format("名称:{0}, 重量:{1}, 是否是鸟类:{2}, 寿命:{3}\r\n",
  27. item.Name,
  28. item.Weight,
  29. (item.isBird ? "是" : "否"),
  30. item.Lifetime);
  31. }
  32. txt_reveal.Text += "匿名查询结果:\r\n" + allAnimals;
  33.  
  34. #endregion
  35.  
  36. //需要分组 且 转换成 Dictionary的情况,用匿名就复杂多了
  37. var animalDic = animalInfo.GroupBy(delegate (AnimalModel p) { return p.Lifetime; })
  38. .ToDictionary(
  39. delegate (IGrouping<decimal, AnimalModel> g) { return g.Key; },
  40. delegate (IGrouping<decimal, AnimalModel> g)
  41. {
  42. return g.OrderBy(delegate (AnimalModel s) { return s; }).ToList();
  43. });
  44.  
  45. }

表达式树中应用

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

由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)的表达式树。

  1. //创建一个表达式树中的参数,作为一个节点,这里是最下层的节点
  2. ParameterExpression w = Expression.Parameter(typeof(int), "w");
  3. ParameterExpression x = Expression.Parameter(typeof(int), "x");
  4.  
  5. //这里w+y,生成表达式树中的一个节点,比上面节点高一级
  6. BinaryExpression wx = Expression.Add(w, x);
  7.  
  8. //创建一个表达式树中的参数,作为一个节点,这里是最下层的节点
  9. ParameterExpression y = Expression.Parameter(typeof(int), "y");
  10. ParameterExpression z = Expression.Parameter(typeof(int), "z");
  11.  
  12. //这里y+z,生成表达式树中的一个节点,比上面节点高一级
  13. BinaryExpression yz = Expression.Add(y, z);
  14.  
  15. //运算两个中级节点,产生终结点
  16. BinaryExpression result1 = Expression.Multiply(wx, yz);
  17.  
  18. Expression<Func<int, int, int, int, int>> lambda = Expression.Lambda<Func<int, int, int, int, int>>(result1, w, x, y, z);
  19.  
  20. //将表达式树描述的lambda表达式,编译为可执行代码,并生成该lambda表达式的委托;
  21. Func<int, int, int, int, int> fa = lambda.Compile();
  22.  
  23. txt_reveal.Text += fa(, , , ) + "\r\n"; //输出结果

编译器处理方式

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

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

式树。

委托

简介

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

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

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

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

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

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

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

Delegate

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

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

例子:

  1. /// <summary>
  2. /// 声明委托
  3. /// </summary>
  4. /// <param name="firstStr">第一个夫字符串</param>
  5. /// <param name="secondStr">第二个字符串</param>
  6. /// <returns></returns>
  7. public delegate string OprateString(string firstStr, string secondStr);
  8.  
  9. /// <summary>
  10. /// Delegate
  11. /// </summary>
  12. /// <param name="sender"></param>
  13. /// <param name="e"></param>
  14. private void btn_delegate_Click(object sender, EventArgs e)
  15. {
  16. DelegateOpt ctStr = new DelegateOpt();
  17.  
  18. //指针连接对象地址
  19. OprateString pttStr = ctStr.ConnectString;
  20.  
  21. //同步直接执行委托
  22. string result= pttStr.Invoke("同学:", "学习委托delegate");
  23.  
  24. //取消绑定,再重新绑定
  25. pttStr-= ctStr.ConnectString;
  26. pttStr += ctStr.ExcludeString;
  27. //指针连接对象地址
  28. IAsyncResult iAsyncRsl = pttStr.BeginInvoke("同学:", "学习委托delegate", null,null);
  29. //主线程中........可在此段时间做其他的事
  30. //Thread.Sleep(1000);//主线程休息2秒钟
  31. string returnStrFromAsyncMethod = pttStr.EndInvoke(iAsyncRsl);//调用EndInvoke返回最终结果
  32.  
  33. txt_reveal.Text = returnStrFromAsyncMethod + "\r\n"; //输出结果
  34. }
  35.  
  36. /// <summary>
  37. /// 连接字符串
  38. /// </summary>
  39. /// <param name="firstStr"></param>
  40. /// <param name="secondStr"></param>
  41. /// <returns></returns>
  42. public string ConnectString(string firstStr, string secondStr)
  43. {
  44. return firstStr + secondStr;
  45. }
  46.  
  47. /// <summary>
  48. /// firstStr 中排除 secondStr
  49. /// </summary>
  50. /// <param name="firstStr"></param>
  51. /// <param name="secondStr"></param>
  52. /// <returns></returns>
  53. public string ExcludeString(string firstStr, string secondStr)
  54. {
  55. return firstStr.IndexOf(secondStr) > - ? firstStr.Replace(secondStr, "") : firstStr;
  56. }

Action中用Lambda

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

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

例子:

  1. /// <summary>
  2. /// 同步获取队列消息
  3. /// </summary>
  4. /// <typeparam name="T">返回的数据类型</typeparam>
  5. /// <param name="action">获取数据后的回调</param>
  6. public void Receive<T>(Action<T> action) where T : class
  7. {
  8. try
  9. {
  10. mqueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
  11. Message message = mqueue.Receive();
  12. T obj = message.Body as T;
  13. if (obj != null)
  14. action(obj);
  15. else
  16. throw new InvalidCastException("队列获取的类型与泛型类型不符");
  17. }
  18. catch (Exception ex)
  19. {
  20. throw ex;
  21. }
  22. }
  1. /// <summary>
  2. /// 接收消息
  3. /// </summary>
  4. /// <param name="queueName">队列</param>
  5. /// <param name="isAsy">是否异步</param>
  6. public user ReceiveMessage(string queueName, bool isAsy)
  7. {
  8. user userInfo = new user();
  9. MessageQueueSettings mqs = new MessageQueueSettings()
  10. {
  11. MessageQueueName = queueName
  12. };
  13. IMessageQueueBase messageQueueBase = new MessageQueueBase(mqs);
  14. if (!isAsy)
  15. {
  16.  
  17. ///直接用lambda 获取接收信息
  18. messageQueueBase.Receive<user>(p =>
  19. {
  20. userInfo = p;
  21. });
  22. }
  23. else
  24. {
  25. messageQueueBase.ReceiveAsync<user>(p =>
  26. {
  27. userInfo = p;
  28. });
  29. }
  30. return userInfo;
  31. }

Func中用Lambda

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

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

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

应用的场景

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. java.util.MissingResourceException: Can't find bundle for base name db, locale zh_CN

    在使用Bundle来加载配置文件的时候, 爆出了这个错误: 原因? 没有找到需要加载的配置文件,因为配置文件必须放在src目录下面, 如果放进了com.bj186.crm的包下面,就必须添加包的名称到 ...

  2. 【原】简单shell练习(三)

    1.软链 linux下的软链接类似于windows下的快捷方式 # ln -s /home/gamestat /gamestat  ln -s a b  中的 a 就是源文件(已经存在的文件),b是链 ...

  3. GRPC在NET上的应用

    GRPC是什么? GRPC是一个开源RPC框架,于2015年3月开源,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于Protobuf 3.0(Protocol Buffer ...

  4. C# Word 类库

    C# Word 类库 2009-08-06 22:10 14292人阅读 评论(11) 收藏 举报 c#objectstring文档microsoftexcel using System;using ...

  5. Java调用WebService接口实现发送手机短信验证码功能,java 手机验证码,WebService接口调用

    近来由于项目需要,需要用到手机短信验证码的功能,其中最主要的是用到了第三方提供的短信平台接口WebService客户端接口,下面我把我在项目中用到的记录一下,以便给大家提供个思路,由于本人的文采有限, ...

  6. python 3 廖雪峰博客笔记(一) python特性

    python 是一种解释性语言,代码在执行时会一行一行翻译成CPU能理解的机器语言. python 的特点是简单优雅. python 的优点是 代码优雅 基础代码库丰富,包括网络.文件.GUI.数据库 ...

  7. Python飞机大战实例有感——pygame如何实现“切歌”以及多曲重奏?

    目录 pygame如何实现"切歌"以及多曲重奏? 一.pygame实现切歌 初始化路径 尝试一 尝试二 尝试三 成功 总结 二.如何在python多线程顺序执行的情况下实现音乐和音 ...

  8. git命令初级

    git是开源的分布式版本控制系统,分布式主要区别于集中式代表CVS(Concurrent Version System,遵从C/S架构,同步比较笨拙.)和SVN(Subversion),linux开发 ...

  9. tomcat无法正确解析请求参数

    24-Mar-2018 14:11:20.564 INFO [http-nio-8080-exec-3] org.apache.coyote.http11.Http11Processor.servic ...

  10. Ubuntu系统搭建django+nginx+uwsgi

    1. 在开发机上的准备工作 2. 在服务器上的准备工作 3.安装uwsgi 4.编写uwsgi配置文件,使用配置文件启动uwsgi 5. 安装nginx 6. 收集静态文件 7. 编写nginx配置文 ...