如果我需要使用LINQ生成一个相当大的数据集,它可能需要一段时间(比如说几秒钟),我需要(想要)生成反馈用于%'年龄完成,是否有一个简单的/首选方式吗?
示例,假设我列出了包含1000辆汽车的列表,列出了包含1000辆卡车的B,我想选择所有可能的订购(汽车,卡车)对,其中car.color == truck.color链接:
var pairs = from car in A
from truck in B
where car.color==truck.color
select new {car, truck};
现在,在某些时候,这将被评估为一组嵌套的foreach循环。我希望能够报告%'年龄完整,因为它可以进行交互并理想地更新进度条或其他内容。
编辑:在我的查询之后,我将结果存储在一个成员变量中作为这样的列表(强制查询执行):
mPairs = pairs.ToList();
我这样做是因为我在后台工作线程中执行它,因为我不希望UI线程冻结,因为它在UI线程上按需评估LINQ表达式(这是在Silverlight BTW中)。因此,为什么我要报告进展情况。用户体验基本上是这样的:
(删除项目时必须执行类似的过程)
答案 0 :(得分:4)
编辑:这当前不起作用,因为查询表达式不允许使用大括号。编辑...
你总是可以添加一个“no-op”select或where子句来显示进度:
public class ProgressCounter
{
private readonly int total;
private int count;
private int lastPercentage;
public ProgressCounter(int total)
{
this.total = total;
}
public void Update()
{
count++;
int currentPercentage = (count * 100) / total;
if (currentPercentage != lastPercentage)
{
Console.WriteLine("Done {0}%", currentPercentage);
lastPercentage = currentPercentage;
}
return true;
}
}
...
var progressCounter = new ProgressCounter(A.Count * B.Count);
var pairs = from car in A
from truck in B
where progressCounter.Update()
where car.color==truck.color
select new {car, truck};
注意使用副作用,这总是令人讨厌。我希望你使用联接,如果这真的是查询,顺便说一下:)
我们一直在考虑将这类运算符添加到MoreLINQ - 称为Pipe,Apply,Via或类似的东西。
答案 1 :(得分:2)
我使用过的效果很好的是DataContext的一个适配器,它返回了它产生的项目数的计数。
public class ProgressArgs : EventArgs
{
public ProgressArgs(int count)
{
this.Count = count;
}
public int Count { get; private set; }
}
public class ProgressContext<T> : IEnumerable<T>
{
private IEnumerable<T> source;
public ProgressContext(IEnumerable<T> source)
{
this.source = source;
}
public event EventHandler<ProgressArgs> UpdateProgress;
protected virtual void OnUpdateProgress(int count)
{
EventHandler<ProgressArgs> handler = this.UpdateProgress;
if (handler != null)
handler(this, new ProgressArgs(count));
}
public IEnumerator<T> GetEnumerator()
{
int count = 0;
foreach (var item in source)
{
// The yield holds execution until the next iteration,
// so trigger the update event first.
OnUpdateProgress(++count);
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
用法
var context = new ProgressContext(
from car in A
from truck in B
select new {car, truck};
);
context.UpdateProgress += (sender, e) =>
{
// Do your update here
};
var query = from item in context
where item.car.color==item.truck.color;
// This will trigger the updates
query.ToArray();
唯一的问题是除非你知道总数,否则你不能轻易做一个百分比。要进行总计数通常需要处理整个列表,这可能是昂贵的。如果您事先知道总计数,那么您可以在UpdateProgress事件处理程序中计算出一个百分比。
答案 2 :(得分:1)
Linq的大部分内容都是使用延迟评估完成的。因此,在您对结果进行预测之前,实际上不会执行查询。每次从对中“拉”结果时,都会评估一部分查询。
这意味着你可以在foreach循环中显示循环,迭代结果。缺点是您事先并不知道结果集的大小,计算结果集的大小也会迭代结果并执行查询。
答案 3 :(得分:0)
var pairs = from car in A
from truck in B
let myProgress = UpdateProgress(...)
where car.color == truck.color
select new { car, truck };
private int UpdateProgress(...)
{
Console.WriteLine("Updating Progress...");
return -1;
}
尽管如上所述,在迭代之前不会执行查询。 这也是在查询中创建新范围变量的另一个缺点。