9

我想要一种方法来更新 IEnumerable 的某些条目。我发现对条目进行 foreach 并更新值失败了,因为我在后台克隆了集合。这是因为我的 IEnumerable 得到了一些 LINQ->SQL 查询的支持。

通过更改获取列表的方法,我改变了这种行为,列表始终是可变的,因此该方法会更改列表中的实际对象。而不是要求传递一个列表,我可以使用一个可变接口吗?

    // Will not behave as consistently for all IEnumerables
    public void UpdateYesterday (IEnumerable<Job> jobs) {
          foreach (var job in jobs.Where(x => x.date == Yesterday)) {
             job.done = true;
          }
    }

    ...

    public class Job {  
         ...           
         public DateTime Date { get; set; }
    }
4

2 回答 2

15

您根本不会在这里更改列表- 集合本身可能是不可变的,并且此代码仍然可以“工作”。您正在更改集合中项目内的数据。

想象一排房子——这是非常不可变的(创建或摧毁房子很棘手),但你仍然可以改变这些房子的内容。

所以,你真正需要知道的是集合的元素是否会被克隆......每次执行查询时你是否会得到一个“新”作业的集合,或者它是否会使用现有的对象。

于 2010-05-18T09:45:59.997 回答
2

这是可能发生的一种假设方式。假设您有一个方法,它采用现有数据源并从该源创建 Job对象。

像这样的东西:

public IEnumerable<Job> GetJobs() {
    var rows = GetRowsFromDatabaseTable();

    foreach (var row in rows)
        yield return new Job(row.Name, row.Date, row.Etc);
}

然后,如果您有执行此操作的代码:

var jobs = GetJobs();

UpdateYesterday(jobs);

foreach (var job in jobs)
    Console.WriteLine(job);

您会发现您使用的打印作业Console.WriteLine并未反映您在UpdateYesterday. 这是因为UpdateYesterday将枚举由创建的新对象GetJobs,然后您的foreach循环将枚举由创建(再次)的一组新对象GetJobs

另一方面,如果您只是将第一行更改为:

var jobs = GetJobs().ToList();

然后,您会将 by 创建的所有这些新对象GetJobs放入一个列表中,它们将在其中保留,因此您的UpdateYesterdayandforeach循环将引用相同的对象(您创建的列表中的对象)。

那有意义吗?我认为这很可能是您遇到的问题(在这种情况下,答案确实是构造一个集合,例如List<Job>内存中的集合,您可以从中访问成员以进行操作)。

在回答您关于能够判断 anIEnumerable是否可变的问题时,虽然......好吧,我真的认为是不可能的。

我已经删除了旧答案,因为新答案似乎是 OP 需要的。

于 2010-05-18T12:48:45.460 回答