Question

I'm a big fan of deferred execution and all that jazz, but now I got slightly different problem.

Consider the following first naïve implementation of a process monitor that simply displays all the processes running on the current machine sorted by 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();
    }
}

(NOTE: the Eval.TryEvalOrDefault<T>(Func<T> f) is just a helper method that I use to evaluate stuff that might throw an exception and return default(T) instead).

Now the thing is that the data source is evaluated only once, precisely at the formation of the query.

And yes, I know, I could just wrap this query definition within a method that keeps recreating it over and over, but I think you can get that my point is to get some-sort of neat trick to make the evaluation of a data-source dynamic, every time that the query is executed.

Was it helpful?

Solution

HA... I think we could pretty much apply the same trick as in the let clause... Define a wrapper that evaluates a Func<IEnumerator<T>> at runtime too!

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();
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top