David Klempfner
David Klempfner

Reputation: 9940

Call methods from a list of Action

I have this code:

        public async Task Execute()
        {
            _count = 0;
            _total = 2; //I need to update this every time I add a new code block below.

            //1st code block
            _progressCallback("Downloading Inspections", _count / _total);
            //do stuff
            _count += 1;

            //2nd code block
            _progressCallback("Downloading Profiles", _count / _total);
            //do stuff
            _count += 1;
        }

I need to keep adding more code blocks, which means I need to keep updating _total.

I thought about doing something like so I don't need to keep updating _total, I can get it from the Count of the List<Action>:

List<Action> functions = new List<Action>();
functions.Add(() => FirstCodeBlock(_count, functions.Count));

Obviously this won't work because functions.Count is only accurate after all the Actions have been added.

Is there some way of writing this code so that I can add blocks of code without having to remember to update _total?

Upvotes: 0

Views: 312

Answers (4)

Enigmativity
Enigmativity

Reputation: 117185

Your code should work fine. The () => FirstCodeBlock(_count, functions.Count) is only executed when you invoke the action. Try this example code:

List<Action> functions = new List<Action>();
functions.Add(() => Console.WriteLine(functions.Count));
functions.Add(() => Console.WriteLine(functions.Count));
functions.Add(() => Console.WriteLine(functions.Count));
functions.ForEach(function => function());  

When I run this I get this:

3
3
3

Upvotes: 1

John Wu
John Wu

Reputation: 52290

Just populate the list ahead of time.

If you store your actions in a Dictionary<string,Action> you can store the messages in there too, which makes it easier to iterate over them in a general fashion.

public void DownloadInspections()
{
    //Code goes here
}

public void DownloadProfiles()
{
    //Code goes here
}

public async Task Execute()
{
    var list = new Dictionary<string,Action>
    {
        { "Downloading inspections", DownloadInspections },
        { "Downloading profiles",    DownloadProfiles    }
    };

    foreach (var item in list)
    {
        //Display progress using the string included as the dictionary entry's key
        _progressCallback(item.Key, _count++ / list.Count);

        //Execute the action, which is stored in the dictionary entry's value
        item.Value();  
    }
}

Upvotes: 1

Kevin
Kevin

Reputation: 590

Your List approach seems like it should work. functions.Count in the lambda isn't evaluated until the lambda is invoked, so if you add all of the actions before you start invoking them, you should be fine.

This is an example of a closure. Since functions is declared outside of the lambda, the compiler does some magic to allow it to be evaluated at invocation time.

Upvotes: 1

ΩmegaMan
ΩmegaMan

Reputation: 31721

This assumes you don't need _count in the activities block,otherwise remove the _count++ / _total.

Because you always have to describe/specify the string'ed named operations, use that as your total. And keep to the pattern.

int _count = 0;
var operations = new List<string>()
{
    "Downloading Inspections",
    "Downloading Profiles"
};

var _total = operations.Count();

_progressCallback(operations[_count], _count++ / _total);

...

_progressCallback(operations[_count], _count++ / _total);

...

Upvotes: 0

Related Questions