兴国安邦

C# 3.0, Linq, Linq To Sql

博客园 首页 新随笔 联系 订阅 管理
  33 Posts :: 0 Stories :: 553 Comments :: 150 Trackbacks
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,是不是抛异常了呢?自己研究下原因哦。
posted on 2007-08-14 21:20 Tom Song 阅读(4417) 评论(12)  编辑 收藏 网摘 所属分类: C# 3.0Linq To Sql

Feedback

呵呵,闭包问题

  回复  引用    

#2楼 2007-08-14 23:52 Lostinet      
这个与C#2.0的行为一致.
  回复  引用  查看    

#3楼 2007-08-15 09:03 cnblogs[未注册用户]
实际就是传值于传引用的问题

  回复  引用    

#4楼[楼主] 2007-08-15 09:15 宋国安      
@Lostinet
是的。是一致的。ms 曾经更改过该处的设计,以实现不用lifting,而最终又担心block现有的code,所以,保留了原来的设计。

  回复  引用  查看    

#5楼 2007-08-15 12:56 hiber[未注册用户]
关于这个己经争论好久了,C#到底是不是完全支持Clourse,不同的人(不同的地方)对Clourse的理解(定义)不一样,看到的结果也就不一样...
  回复  引用    

#6楼 2007-08-16 16:41 headchen      
凡是函数式编程,Closure是最基本的概念。用过javascript的人都会很清楚这一点。
  回复  引用  查看    

#7楼 2007-08-16 16:43 迭戈      
你好:请教一下。
OrderDataContext db = new OrderDataContext();
string[] keyWords = new string[] { "A", "B", "C", "D" };
var q = from c in db.Customers
select c;
foreach (string keyWord in keyWords)
{
string TempStr = keyWord;
q = q.Where(temp => temp.CustomerID.Contains(TempStr));
}
var Result = q.ToArray();


为什么返回为空的。数据库是有匹配的。谢谢

  回复  引用  查看    

#8楼[楼主] 2007-08-16 18:15 宋国安      
@迭戈
它是And 呀
CustomerID like '%A%' and like '%B%' and....

你确定有这样的记录?

  回复  引用  查看    

#9楼 2007-08-17 08:44 迭戈      
@宋国安
它是And 呀
CustomerID like '%A%' and like '%B%' and....

你确定有这样的记录?

原来。不过我想是or的关系。如何实现。谢谢

  回复  引用  查看    

#10楼 2007-08-28 15:08 Cheney Shue      
好文章
  回复  引用  查看    

#11楼 2007-09-18 20:35 镜涛      
好东东哦!
  回复  引用  查看    

#12楼 2008-01-18 17:10 Silent Void      
@迭戈
实现or:
foreach (string keyword in keyWords)
{
var key = keyword;
entitys.Union(entitys.Where(e => e.Contains(key)).ToList());
}

  回复  引用  查看    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 855824




历史上的今天:
2006-08-14 C# 3.0 入门系列(一)

相关文章:

相关链接: