在大型数据集上执行LINQ表达式时如何报告进度

car*_*den 5 linq

如果我需要使用LINQ生成相当大的数据集,并且可能要花一些时间(例如几秒钟),并且我需要(希望)生成有关使用情况的反馈信息,是否有简单/首选的方法去做这个?

例如,假设我有1000辆汽车的列表A和100​​0辆卡车的列表B,并且我想选择所有可能的有序(汽车,卡车)对,其中car.color == truck.color链接如下:

var pairs = from car in A 
            from truck in B 
            where car.color==truck.color 
            select new {car, truck};
Run Code Online (Sandbox Code Playgroud)

现在,将在某些时候将其评估为一组嵌套的foreach循环。我希望能够报告完成的%%年龄,并且可以理想地更新进度条或其他内容。

编辑:查询后,我将结果存储在一个成员变量中,像这样的列表(这将强制执行查询):

mPairs = pairs.ToList();
Run Code Online (Sandbox Code Playgroud)

我这样做是因为我在后台工作线程中执行此操作,因为我不希望UI线程冻结,因为它会按需评估UI线程上的LINQ表达式(这在Silverlight BTW中)。因此,为什么我要报告进度。UX基本上是这样的:

  1. 用户将项目拖到工作区上
  2. 然后,引擎在后台线程中启动,以确定到工作空间上所有其他项目的(许多)连接可能性。
  3. 在引擎计算期间,UI不允许新连接,并且报告进度以指示新项目何时将“可连接”到其他项目(尚未使用的所有可能的连接路径已通过LINQ确定)。
  4. 当引擎完成计算(查询)时,该项目可在UI中连接,并且可能的连接路径存储在本地变量中以备将来使用(例如,当用户单击以连接该项目时,所有可能的路径将基于添加时的计算结果)

(删除项目时必须执行类似的过程)

Cam*_*and 4

我使用的效果很好的是 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

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();
Run Code Online (Sandbox Code Playgroud)

唯一的问题是,除非您知道总数,否则您无法轻松计算百分比。要进行总数计数通常需要处理整个列表,这可能会很昂贵。如果您事先知道总计数,则可以在 UpdateProgress 事件处理程序中计算出百分比。