除了行为,我对以下的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();
}
}
Run Code Online (Sandbox Code Playgroud)
但是显然不是这样。在调试器中检查时,list3包含{Obj('a'),Obj('b')},并且这些对象不是list1包含的引用的等同对象。和Obj构造函数被调用4次。
linq不应该Where和Excet方法只是将对象引用从一个IEnumerable复制到另一个IEnumerable吗?创建对象副本的对象是谁?
问题在于您的列表并不是真正的列表-它们是延迟计算的序列。该代码执行时:
var list1 = "a,b"
.Split(',')
.Select(x => new Obj(x));
Run Code Online (Sandbox Code Playgroud)
... Split立即被调用,然后Where被调用以在该数组上建立延迟评估的序列。如果您根本不进行迭代list1,Obj则不会创建的实例。如果迭代list1多次,则每次都会获得新对象。
所有你需要做的就是你的代码工作是兑现通过转换为一个列表(或阵列将工作太)查询:
var list1 = "a,b"
.Split(',')
.Select(x => new Obj(x))
.ToList();
Run Code Online (Sandbox Code Playgroud)
另外,您可以覆盖Equals和GetHashCode中的Obj,这样就Except可以适当地考虑不同但相等的对象。