Translate nested anonymous functions to foreach loop

217 views Asked by At

Trying to optimise some code I ended up having this kind of structure:

StaticMethod(propA, () => 
{
    StaticMethod(propB, () => 
    {
        StaticMethod(propC, () => 
        {
            // Write line in console here to say it's done.
        });
    });
});

And I was thinking there should maybe be a way to simplify that to some foreach or even a simple for loop, something like this:

foreach (var prop in props) // consider that `props` can be iterated over
{
    // Here I don't know how to chain everything...
}

Is this any doable ? Do I need to modify StaticMethod to achieve this ? The loop may not be enough alone, but extending the example to 1000 nested functions, I would need some iteration.

Here's the concept of StaticMethod:

static void StaticMethod(Prop prop, Action done) 
{
    // Some code here
    someDispatcher.BeginInvoke(() => {
        // More code here
        done();
    });
}
1

There are 1 answers

12
Servy On BEST ANSWER

This is indeed a problem that is extremely difficult with a callback based model of asynchrony. If you transform StaticMethod into a Task based model of asynchrony then the solution becomes much simpler. If StaticMethod is your own method, you'd ideally just re-write it using a Task based model entirely, where it returns a Task when it has finished, rather than taking a callback, but if it's not your method, and you can't change it, you can create a wrapper that uses a Task based model. To transform a callback based method into a Task based method you simply use a TaskCompletionSource:

public static Task StaticMethodAsync(object a)
{
    var tcs = new TaskCompletionSource<bool>();
    StaticMethod(a, () => tcs.SetResult(true));
    return tcs.Task;
}

Now that we have that we can write an async method that iterates over props and calls each asynchronous method in turn:

foreach (var prop in props)
{
    await StaticMethodAsync(prop);
}
// Write line in console here to say it's done.

If you really want to solve this problem while maintaining a callback model, you can, but, as you can see below, it's much harder to read, understand, and step through:

public static void Foo(object[] props, Action callback)
{
    int i = -1;
    Action innerCallback = null;
    innerCallback = () =>
    {
        i++;
        if (i < props.Length)
        {
            StaticMethod(props[i], innerCallback);
        }
        else
        {
            callback();
        }
    };
    innerCallback();
}