Question

I have a big long looping procedure like this:

public void Process()
{
    bool done = false;
    do {
        //do stuff
    }while (!done);
}

that I'd like to chop into bits and have the calling routine display my progress in some sort of UI. It's a class library, so the caller may be anything (Console App, WinForms, WebApp, ...).

It would be easiest if I could do:

public void Process()
{
    bool done = false;
    do {
        //do stuff
        yield return;
    }while (!done);
}

So the caller could keep calling the method until it's done.

This smells more like a job for BackgroundWorker, but that seems "wrong" for a Console App... I won't always NEED multithreading. Or does it? I mean, yeah, I could just have the console's main thread just wait for it to finish.

My question is: Can I use the "piecemeal" deferred execution functionality of "yield return" without actually returning something?

Was it helpful?

Solution 2

In short, no.

yield return has to return something.

http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx

The Process method should have a return type of IEnumerable, IEnumerable<T>, IEnumerator, or IEnumerator<T>. You may return dummy objects if you really want to use yield.

You might want to investigate different ways to report progress to the caller.

OTHER TIPS

The language feature you want is called a coroutine (or, more precisely, a semicoroutine, but let's not be pedantic.) C# iterator blocks are a weak form of coroutine. I recommend against making "dummy" sequences just because you want coroutines.

The await operator in C# 5 is also a form of coroutine and might more closely resemble your desired solution, particularly if your operation is logically an asynchronous, high-latency operation. There are standard patterns for progress reporting with asynchronous coroutines in C# 5; I would start by reading this:

http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx

As already someone else answered, no that's not the way to go, but why don't you simply use a callback Func or Action or something to let the callee interact with your loop?

public void Process(Action callback)
{
    bool done = false;
    do {
        //do stuff
        callback();
    }while (!done);
}

Or use some other kind of event handling which is typically used for stuff like that.

You say you want the caller to respond to progress of the method. You could return progress information:

class ProgressInfo { ... }
...
yield return new ProgressInfo() { ... };

The caller would then foreach over the results and act on them.

This is much nicer than having the caller examine global mutable state. This is a functional solution.

No, not possible. Compiler generates iterators for you only when the return type is IEnumerable or IEnumerator.

A workaround would be return some value and change the return type of the method to make compiler happy.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top