2011-05-24 39 views
1

我正在使用linq通过一个门面对象通过Id选择一堆对象。这个门面有一个函数GetObjectById(string id)它返回一个MyObject。我选择基于ID的列表上一个查询一堆对象:Linq到对象不“持续”的变化

IEnumerable<MyObject> objects = 
    from id in ids 
    select facade.GetObjectById(id); 

再后来我把我的对象一定的价值,像这样:

foreach(MyObject object in objects) 
{ 
    object.someValue = "banaan"; 
} 

后来当我检查对象的IEnumerable, someValue未设置为“banaan”。

它看起来像它与linq的延期执行有关,因为当我把.ToList()放在第一个查询后面时我确实有效。但是,我认为我应该可以做这样的事情。我在这里做错了什么?或者是我的理解你应该如何使用linq错误?

在此先感谢。

回答

2

当然,这是延迟执行的问题。如果查询再次执行,它将在期间再次调用您的Facade方法,并且如果Facade方法从某处加载数据(=创建新实例),则以前的更改将丢失。您的foreach是第一次执行,第一次执行时检查第一个foreach是第二次执行。

如果您想在这种情况下对相同的实例进行操作,则必须调用ToList

1

当您第二次检查对象时,是否重新评估objects可枚举?因为这会让它再次调用facade.GetObjectById(id)。

试着改为实现enumerable。像这样:

IEnumerable<MyObject> objects = 
    (from id in ids 
    select facade.GetObjectById(id)).ToArray(); 
+0

但是,这不是我的清单的副本?我有几个这样的功能,互相呼叫。即GetObjectsById(IEnumerable ID)调用GetObjectById。它会每次都被复制,并会打破延期执行的好处吗?我认为延期执行并不意味着:每次执行都重复执行。 – 2011-05-24 12:39:57

+0

如果没有ToArray/ToList,实际上根本没有任何列表,只是重新创建枚举的一种方式。当您最多一次迭代集合时,您只能从延迟执行中获益。 – CodingInsomnia 2011-05-24 12:45:14

+0

顺便说一句,如果你想真正理解LINQ以及幕后发生了什么,我推荐阅读Jon Skeets Edulinq系列博客文章(现在可用电子书格式):http://msmvps.com/blogs/jon_skeet/archive /2011/03/18/edulinq-the-e-book.aspx – CodingInsomnia 2011-05-24 12:54:10

0

我假设你正在运行SQL Server的某个地方的数据来自哪里?

查询将保留在LINQ to SQL空间中,直到您在前面的答案中建议您调用ToList()或ToArray()或类似方法。只有这样它才能真正成为LINQ to Object,并且是实例化的数据,并且它会保存在程序的内存空间中。

通过这种方式,在对列表进行更改后,您可以再次执行相同的查询并获取其中没有更改的其他列表。

也许更好的解释如下:

(from id in ids select facade.GetObjectById(id)).Where(o=>string.IsNullOrEmpty(o.Name)) 

因为没有翻译从string.IsNullOrEmpty到SQL这会给出一个错误。

(from id in ids select facade.GetObjectById(id)).ToList().Where(o=>string.IsNullOrEmpty(o.Name)) 

这不会给出错误,因为在ToList()之后,你在对象空间中。

+0

我没有使用SQL Server,只是对象(来自WCF服务)。 – 2011-05-24 12:50:15