C#3.0入门系列(四)

转载 2007年09月12日 15:00:00

Lambda表达式中Lifting

Lambda表达式是由匿名方法演化而来的更加高级的形式。关于匿名方法,请参阅http://msdn.microsoft.com/msdnmag/issues/04/05/C20/。关于Lambda表达式的演化,请参阅http://msdn.microsoft.com/msdnmag/issues/07/06/csharp30/default.aspx?loc=zh。英文原版为http://msdn.microsoft.com/msdnmag/issues/07/06/CSharp30/

1,Lambda表达式中的lifting
在c# 2.0中,匿名方法的使用,是这样的。

class SomeClass
{
   
delegate void SomeDelegate();
   
public void InvokeMethod()
   
{
      SomeDelegate del 
= delegate() 
                         
{
                             MessageBox.Show(
"Hello");
                         }
;
      del();   
   }

}


在LINQ 的演变及其对 C# 设计的影响 一文中,其断言如果 lambda 表达式首先被引入语言,那么就不会有对匿名方法的需要了。在本系列前面的一些文章中,也曾提到lambda 表达式,但并没有做太深入的引述。本文所要讲的是Lambda表达式中lifting,将开始和大家体会lambda表达式的一些细节。

编译下面的小程序,看看输出结果,是不是大吃一惊
using System;
using System.Collections.Generic;
using System.Linq;

namespace Tester
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            List
<Func<int>> list = new List<Func<int>>();

            
for (int i = 0; i < 3; i++)
            
{
                list.Add(() 
=> i);
            }


            
foreach (var item in list)
            
{
                Console.WriteLine(item());
            }

        }

    }

}

我们定义了一个list,其存储格式为func<int>,即返回int型的代理。而后,用for循环,将 i  封装进lambda表达式,并加入到该list中。而后,用foreach循环输出结果。因为lambda表达式,其实质就是个代理,也就指向一个匿名函数,所以,使用item()来调用它,让所指向的函数执行。

问题是,你所盼望输出,0,1,2,而实际结果均是3。为什么会这样呢?这牵扯到两个原因。
第一,在for循环中,只能有一个 i 变量。即再第一次循环时,i 的地址就分配好了,不会因为循环次数的多少而发生任何改变,其改变的只能是里面装载的值。

第二,lambda表达式在构造时, 传进去的是变量的地址,而不是具体值。只有当真正执行这个lambda表达式时,才会去确定它的值。这就是为什么上面的例子中,其结果均为3。(for循环在最后,又给 i 加了1)

我们可以很容易,就将起解决掉。在for循环中,定义一临时变量,存储 i  的值即可。因为编译器会对该临时变量重新分配内存,这样,每次循环,都重新分配新的内存,就不会有这个问题了。再来运行下面的这个例子。
using System;
using System.Collections.Generic;
using System.Linq;

namespace EnterpriseTester
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            List
<Func<int>> list = new List<Func<int>>();

            
for (int i = 0; i < 3; i++)
            
{
                
int temp = i;
                list.Add(() 
=> temp);
            }


            
foreach (var item in list)
            
{
                Console.WriteLine(item());
            }

        }

    }

}
是不是满足了你的要求了呢?这个temp,就称为lifting。lift是美语中的电梯,翻译为梯子或垫脚石,比较妥帖。

2,lifting在Linq To Sql中的影响。
Lambda表达式在Linq To Sql中大量应用,这个问题势必要影响到其sql语句的形成。看下面的例子
          string[] keyWords  = string[] keyWords = new string[] "111""222""333""444" };
            SomeDataContext ctx 
= new SomeDataContext ();
            var entitys 
= from e in ctx.Entity
                           select e;
            
foreach (string keyWord in keyWords)
            
{
                entitys 
= entitys.Where(e => e.Text.Contains(keyWord));
            }
               var q = entitys.ToList();
本意是想查找,全部满足模糊匹配的所有记录,其实际生成的sql语句中,只传入了“%444%”。加个lifting吧,问题就解决了。
大家可以用for循环替换foreach循环,如果,不加lifting,是不是抛异常了呢?自己研究下原因哦。
 

Wireshark入门与进阶系列四之过滤语法

0x00 前言     我们都知道,wireshark可以实现本地抓包,同时Wireshark也支持remote packet capture protocol(rpcapd)协议远程抓包,只要在远...
  • qq_29277155
  • qq_29277155
  • 2016年07月30日 20:24
  • 1511

C#3.0入门系列(三)

 GroupBy操作 换一种写作风格。本节讲groupby操作。在所有的Linq To Sql操作中,GroupBy是最难理解的一个。因为,这里和Sql的出入较大。而Group真的就能返回n多组。打开...
  • lincnl
  • lincnl
  • 2007年09月12日 14:56
  • 829

“Ceph浅析”系列之四Ceph的结构

本文将从逻辑结构的角度对Ceph进行分析。 4.1    Ceph系统的层次结构         Ceph存储系统的逻辑层次结构如下图所示[1]。         自下向上,可以将Ceph系统...
  • qq_24916117
  • qq_24916117
  • 2015年12月30日 20:42
  • 542

C#3.0 有哪些新特性?

1:隐式类型化本地变量 这个特性非常简单,有些JavaScript的影子,我们可以统一使用使用”var”关键字来声明局部变量,而不再需要指明变量的确切类型了,变量的确切类型可通过声明变量时的初始值推...
  • new0801
  • new0801
  • 2017年02月07日 11:39
  • 318

四旋翼入门

基础版:共十篇 1.入门必读,这个文章针对性很强,理论也很基础 Modeling, Estimation,and Control of Quadrotor 2.介绍了APM及其他开源飞控的硬件及...
  • u013401056
  • u013401056
  • 2016年06月22日 21:41
  • 810

USB入门系列之一:USB概述

USB是什么呢?一说USB是You SB的意思,即“你傻B”的意思。另一种说法是USB其实是美国的弟弟,因为美国叫USA,USB当然是他的弟弟了。...
  • kevinhg
  • kevinhg
  • 2010年09月30日 23:44
  • 2116

Java学习笔记_身份验证机制

身份验证机制(authentication):确定一个用户具有自己声称的那个身份 应用程序关心用户是否通过了验证而不关心是通过何种方式进行的验证??? 授权(访问控制:authorization):★...
  • SmartTony
  • SmartTony
  • 2008年03月07日 20:25
  • 1018

SpringBoot入门系列之第一篇:HelloWorld

springboot快速构建 spring initializr生成项目 springboot其他创建方式 springboot restful简单访问 项目简单重构springboot快速构建spr...
  • ihaveFilter
  • ihaveFilter
  • 2017年07月05日 16:33
  • 130

小鑫の日常系列故事(四)——乘法计算

小鑫の日常系列故事(四)——乘法计算 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 小鑫在上小学的时候,学会了...
  • guoqingshuang
  • guoqingshuang
  • 2015年11月20日 16:47
  • 249

看雪学院-OllyDBG入门系列(二)笔记

OllyDBG 入门系列(二)-字串参考 笔记 原作地址:http://bbs.pediy.com/showthread.php?threadid=21308 作者:CCDebuger   软...
  • Cytosine
  • Cytosine
  • 2017年02月04日 15:10
  • 329
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C#3.0入门系列(四)
举报原因:
原因补充:

(最多只允许输入30个字)