[英]surprising linq except behavior
除了行为之外,我对以下的linq感到非常惊讶,有人可以解释为什么吗? 我列出了我对linq如何工作的理解/假设。 其中至少有一个是错的。
public class Obj {
public string Name;
public Obj(string name)
{
this.Name = name;
}
}
class Program
{
public static void Main(string[] args)
{
var list1 = "a,b"
.Split(',')
.Select(x => new Obj(x));
var list2 = list1.Where(x => x.Name == "b");
var list3 = list1.Except(list2).ToList();
}
}
但显然,事实并非如此。 在调试器中检查时,list3包含{Obj('a'),Obj('b')},并且这些对象不是list1包含的引用的等号。 Obj构造函数被调用4次。
不应该linq Where和Excet方法只是将对象引用从一个IEnumerable复制到另一个IEnumerable? 谁在创建对象副本?
问题是你的列表不是真正的列表 - 它们是懒惰的评估序列。 当此代码执行时:
var list1 = "a,b"
.Split(',')
.Select(x => new Obj(x));
...立即调用Split
,然后调用Where
以在该数组上设置一个延迟计算的序列。 如果您根本不迭代list1
,则不会创建Obj
实例。 如果多次遍历list1
,则每次都会获得新对象。
所有你需要做的就是你的代码的工作是通过转换为一个列表(或阵列将工作太) 物化查询:
var list1 = "a,b"
.Split(',')
.Select(x => new Obj(x))
.ToList();
或者,您可以在Obj
重写Equals
和GetHashCode
,以便Except
适当地考虑不同但相等的对象。
如果你使用foreach,它会调用IEnumerator.MoveNext()
而它将是新的Object
public class Obj
{
public string Name;
public Obj(string name)
{
Debug.LogFormat("HI");
this.Name = name;
}
}
var list1 = "a,b"
.Split(',')
.Select(x => new Obj(x));
foreach (var v in list1)
{ }
输出:HI HI
如果你运行两个foreach,它将Inovke Double IEnumerator.MoveNext()
foreach (var v in list1)
{ }
foreach (var v in list1)
{ }
输出:HI HI HI HI
所以与使用Except和toList相同,它也像foreach list1一样
var list2 = list1.Where(x => x.Name == "b");
var list3 = list1.Except(list2);// output HI HI
list3.ToList();// output HIHI
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.