如何处理LINQ中的源数据更改?

时间:2010-11-11 16:00:55

标签: c# linq

我有一个项目集合,其中每个项目都有一个“日期”字段(代码如下)。

我正在尝试使用LINQ填充集合中日期的任何空白。特别是,我希望结果序列包含原始序列中第一天和最后一天之间的所有日子。

除此之外,我生成的LINQ查询应该能够处理原始序列的任何修改。那是我无法提前计算最小和最大日期。

所以我尝试了下面的代码,但是当它试图计算序列的最小值和最大值时它失败了。我正在寻找一个“懒惰”的选择。

感谢您的帮助 康斯坦丁


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace consapp
{
    class C
    {
        public DateTime date;
        public int? value;
    }

    static class Program
    {
        static IEnumerable<C> dates(DateTime d0, DateTime d1)
        {
            for (var d = d0; d <= d1; d = d.AddDays(1))
            {
                yield return new C { date = d };
            }
        }

        static void Main(string[] args)
        {
            var xs = new ObservableCollection<C>();

            var q = from d in dates(xs.Min(y => y.date), xs.Max(y => y.date))
                    join x in xs on d.date equals x.date into js
                    from j in js.DefaultIfEmpty()
                    orderby d.date
                    select new { date = d.date, value = j != null ? j.value : null };

            xs.Add(new C { date = DateTime.Parse("11/10/11") });
            xs.Add(new C { date = DateTime.Parse("02/02/11") });
            xs.Add(new C { date = DateTime.Parse("11/24/11") });
            xs.Add(new C { date = DateTime.Parse("09/09/11") });
            xs.Add(new C { date = DateTime.Parse("11/10/11") });

            foreach (var x in q)
            {
                Console.WriteLine(x.date.ToShortDateString());
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我不是绝对肯定的,但是:

var q = from d in dates(xs.Min(y => y.date), xs.Max(y => y.date))

我相信会立即调用“dates”方法,而LINQ查询的其余部分(包括来自dates()本身的迭代器)将围绕该方法的结果构建。因此,您必须使用您感兴趣的数据预先填充xs

这是因为LINQ基本上是通过将枚举包装在其他可枚举中来实现的。为了使它能够执行此操作,它必须以可枚举的方式开头。为了做到这一点,它必须调用你的order()方法,需要立即提供它的参数,以便它可以接收它将包装在其他枚举中的可枚举对象。因此,当到达该行代码时,将调用xs.Minxs.Max方法,但实际上不会处理查询中的任何其他内容。

解决方法是让您的dates()方法实际收到ObservableCollection并致电Min / Max本身。因为这将在生成的迭代器中发生,所以这些调用的执行将按预期延迟。

答案 1 :(得分:0)

基于IEnumerable<T>的标准LINQ实现无法处理正在发生变化的数据源,例如ObservableCollection。您的示例失败的原因是,当您定义查询(但数据源)时,它将尝试评估数据源(并调用dates函数以及MinMax运算符)此时不包含任何数据。)

  • 一种选择是使用与ObservableCollection一起使用的替代LINQ实现,并且可以在源更改时自动更新结果。据我所知Bindable LINQ项目应该能够做到这一点。

  • 另一个(更简单的)选项是将查询转换为方法,并在知道数据源已更改时重复调用该方法(以更新结果)。您必须将ObservableCollection设为私有字段,该方法只需使用当前存储在集合中的数据运行:

    private ObservableCollection source;
    void UpdateResults() { 
      var q = /* The query goes here */
      // Do something with the result of the query
    }