首页 新闻 会员 周边 捐助

Linq的延时查询问题

0
悬赏园豆:5 [已关闭问题] 关闭于 2010-12-30 17:39

IEnumerable<char> query = "Not what you might expect";
foreach (char vowel in "aeiou")

{

  char temp = vowel;

  query = query.Where (c => c != temp);

}
query.Dump ("The workaround");

 

IEnumerable<char> query = "Not what you might expect";

foreach (char vowel in "aeiou")

{

  query = query.Where (c => c != vowel); 

}

 new string (query.ToArray()).Dump ("Notice that only the 'u' is stripped!");

 

前面两个查询为什么结果会不一样,一直没弄明白。

为什么第一个循环里加了个变量后就不一样了呢。

希望高手解惑。

 

这是LinqPad里的例子。

遥远的记忆的主页 遥远的记忆 | 初学一级 | 园豆:199
提问于:2010-11-30 17:43
< >
分享
所有回答(2)
0

你好,这个问题是这样的。

首先你应该理解Linq的迟绑定的原理,因为你不理解这个,你的例子的区别你将无法解答。

所谓linq的迟绑定,就是你的linq语句的执行是在query.ToArray()中执行的。

还有,你应该明白扩展方法中变量的声明周期。

好了,如果你明白了上面所说的,接下来我们来看你的第一个和第二个的区别:

第一个:

            IEnumerable<char> query1 = "Not what you might expect";
            var result = query1.Where(c => c != 'a');
            result = query1.Where(c => c != 'e');
            result = query1.Where(c => c != 'i');
            result = query1.Where(c => c != 'o');
            result = query1.Where(c => c != 'u');

 

第二个:

            IEnumerable<char> query2 = "Not what you might expect";
            query2 = query2.Where(c => c != 'u');
            query2 = query2.Where(c => c != 'u');
            query2 = query2.Where(c => c != 'u');
            query2 = query2.Where(c => c != 'u');
            query2 = query2.Where(c => c != 'u');

 

希望能帮助你。

S.Chen | 园豆:205 (菜鸟二级) | 2010-11-30 20:25
我还是不理解 为什么第一个查询的循环语句中添加了char temp = vowel;语句结果就不一样。
支持(0) 反对(0) 遥远的记忆 | 园豆:199 (初学一级) | 2010-12-01 12:14
因为每次你循环的时候,char temp都是重新定义的,应此每一次创建的temp都是一个新的char对象,查询的时候,对应的就是五个不同值的char对象。 而第二个查询,是只有一个 char 对象的,每次晕环,都是对同一个char对象进行复制。到最后执行这个查询的时候,就是如上说所的了。
支持(0) 反对(0) S.Chen | 园豆:205 (菜鸟二级) | 2010-12-01 14:00
0

其实最终是个传值和传地址的问题,只了解表面现象倒也不是问题……

Gray Zhang | 园豆:17610 (专家六级) | 2010-11-30 22:24
你好,我有不同的意见: 我认为这个问题,不是传值和传地址的问题。这是由于linq的迟绑定所引发的一个问题。 因为当两个查询各自真正excute的时候,第一个查询由于比较的字符是不同的对象。 而第二个查询比较的字符是同一个对象,到最后循环结束,对象的值就是最后一个赋值的值。所以就产生这样的现象了。 如果把第一个查询给成 IEnumerable<char> query = "Not what you might expect"; char temp; foreach (char vowel in "aeiou") { temp = vowel; query = query.Where(c => c != temp); } 这样,这个查询也和第二个结果是一样的了,就是因为对象是同一个对象,执行的时候是五个相同的查询,即 IEnumerable<char> query1 = "Not what you might expect"; var result = query1.Where(c => c != 'a').Where(c => c != 'e').Where(c => c != 'i').Where(c => c != 'o').Where(c => c != 'u');
支持(0) 反对(0) S.Chen | 园豆:205 (菜鸟二级) | 2010-12-01 09:08
本质是,因为延迟绑定,而这里的c这个变量一直是按地址传的,经过Where不断地修改c这个地址中的内存的内容,最后变成了"u",再返过来,延迟的绑定开始执行,因此c全部是"u"
支持(0) 反对(0) Gray Zhang | 园豆:17610 (专家六级) | 2010-12-01 15:02
真的是传值吗?char的变量在传值的时候,都是按照值类型在传递的,也就是说直接传送的是背后的值。 只不过这里:第一个相当于有5个char的对象,可以理解为temp1,temp2。。。temp5, 而第二个只有一个char对象,vowel。给它赋了5次值。 而并没有涉及传递是引用还是值的问题。
支持(0) 反对(0) S.Chen | 园豆:205 (菜鸟二级) | 2010-12-01 15:56
不是传值也不是传引用,而是传地址,相当于一直使用ref传参
支持(0) 反对(0) Gray Zhang | 园豆:17610 (专家六级) | 2010-12-01 17:13
你说这里的char对象是ref传进去的是把? 那么下面这段代码做何解释。我已经在上面说的很详细了,这个问题是由于linq查询绑定了不同对象和绑定了同一个对象造成的结果。请Gray Zhang 再好好思考一下。 IEnumerable<char> query = "Not what you might expect"; char temp; foreach (char vowel in "aeiou") {   temp = vowel;   query = query.Where (c => c != temp); }
支持(0) 反对(0) S.Chen | 园豆:205 (菜鸟二级) | 2010-12-01 19:22
我不明白你这个说明什么,因为c是保留地址的,假设c变量的地址是0x01。第1次:vowel=a,temp=a,c=a,但是没执行。第2次:vowel=e,temp=e,c=e,因为这个c用的是地址0x01,相当于把0x01这个内存位置的内容改成了'e',连带第一次形成的c=a也变成了c=e。依次类推,最后必然会出现vowel=temp=c='u',随后去执行LINQ的查询,相当于执行了5次c => c != 'u'
支持(0) 反对(0) Gray Zhang | 园豆:17610 (专家六级) | 2010-12-01 21:53
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册