我有一个项目集合,其中每个项目都有一个“日期”字段(代码如下)。
我正在尝试使用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());
}
}
}
}
答案 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.Min
和xs.Max
方法,但实际上不会处理查询中的任何其他内容。
解决方法是让您的dates()
方法实际收到ObservableCollection
并致电Min
/ Max
本身。因为这将在生成的迭代器中发生,所以这些调用的执行将按预期延迟。
答案 1 :(得分:0)
基于IEnumerable<T>
的标准LINQ实现无法处理正在发生变化的数据源,例如ObservableCollection
。您的示例失败的原因是,当您定义查询(但数据源)时,它将尝试评估数据源(并调用dates
函数以及Min
和Max
运算符)此时不包含任何数据。)
一种选择是使用与ObservableCollection
一起使用的替代LINQ实现,并且可以在源更改时自动更新结果。据我所知Bindable LINQ项目应该能够做到这一点。
另一个(更简单的)选项是将查询转换为方法,并在知道数据源已更改时重复调用该方法(以更新结果)。您必须将ObservableCollection
设为私有字段,该方法只需使用当前存储在集合中的数据运行:
private ObservableCollection source;
void UpdateResults() {
var q = /* The query goes here */
// Do something with the result of the query
}