延期执行与延期**数据源**评估

时间:2012-08-01 19:20:10

标签: c# .net linq-to-objects deferred-execution

我是延迟执行和所有爵士乐的忠实粉丝,但现在我的问题略有不同。

考虑以下第一个天真的流程监视器实现,它简单地显示在当前机器上运行的所有进程,按StartTime排序:

public partial class ProcessesByStartTimeForm : Form {

    // ... init stuff

    public static readonly IEnumerable<object> ProcessQuery
        = from p in Process.GetProcesses()
          let startTime = Eval.TryEvalOrDefault<DateTime?>(() => p.StartTime)
          orderby startTime
          select new {
              Process = p.ProcessName,
              StartTime = startTime, // could be null
              Title = p.MainWindowTitle
          };

    private void ProcessesByStartTimeForm_Load(object sender, EventArgs e) {
        this.RefreshDataSource();
    }

    private void refreshToolStripMenuItem_Click(object sender, EventArgs e) {
        this.RefreshDataSource();
    }

    private void RefreshDataSource() {
        this.gridView.DataSource = ProcessQuery.ToList();
    }
}

(注意:Eval.TryEvalOrDefault<T>(Func<T> f)只是一个帮助方法,我用它来评估可能引发异常并返回default(T)的东西。)

现在的问题是数据源只被评估一次,恰好是在查询的形成时。

是的,我知道,我可以将这个查询定义包装在一个一遍又一遍地重新创建它的方法中,但我认为你可以得到我的观点是得到一些巧妙的技巧来评估每次执行查询时都是数据源动态。

1 个答案:

答案 0 :(得分:0)

HA ...我认为我们几乎可以应用与let子句中相同的技巧...定义一个在运行时评估Func<IEnumerator<T>>的包装器!

public partial class ProcessesByStartTimeForm : Form {

    // ... init stuff

    public static readonly IEnumerable<object> ProcessQuery
        = from p in new DeferredEnumerable<Process>(() => Process.GetProcesses())
          let startTime = Eval.TryEvalOrDefault<DateTime?>(() => p.StartTime)
          orderby startTime
          select new {
              Process = p.ProcessName,
              StartTime = startTime, // could be null
              Title = p.MainWindowTitle
          };

    class DeferredEnumerable<T> : IEnumerable<T> {
        readonly Func<IEnumerable<T>> f;

        public DeferredEnumerable(Func<IEnumerable<T>> f) {
            this.f = f;
        }

        public IEnumerator<T> GetEnumerator() {
            return this.f().GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
            return this.GetEnumerator();
        }
    }
}