On 26 April 2016 at 09:51, Greg Keogh <[email protected]> wrote:
> Now I'm trying to shrink this down to the smallest possible
>>> functional-looking code possible
>>>
>>
>>
>>> new Action(async () => { var r = await GetStuffAsync("Key1");
>>> updateUI(r) }).Invoke();
>>> new Action(async () => { var r = await GetStuffAsync("Key2");
>>> updateUI(r) }).Invoke();
>>> new Action(async () => { var r = await GetStuffAsync("Key3");
>>> updateUI(r) }).Invoke();
>>>
>>
> I wasn't very clear originally, but I guess what I'm really looking for is
> the shortest and most elegant C# code that can fire off an arbitrary number
> of independent await-and-UI-updates like above. I do want to avoid
> splitting it into multiple methods.
>
> I know the code above is a bit chunky looking and lacks functional beauty,
> but besides writing this stuff in F# I'm not sure how to strip it down
> further. Suggestions are welcome!
>
You can shorten "f.Invoke()" to just "f()". You can elide "r" as well:
new Action(async () => UpdateUI(await GetStuffAsync("key1")))();
new Action(async () => UpdateUI(await GetStuffAsync("key2")))();
new Action(async () => UpdateUI(await GetStuffAsync("key3")))();
If you want to make it cleaner still (i.e. get rid of the unnecessary
Action delegate), I think you will have to write a method. Personally, I
would write a method anyway to separate the re-usable parts from the
arguments, and to separate the pattern/policy from the
implementation/boilerplate. Note also that by inlining it everywhere as you
have done here, a separate method body will be compiled for each lambda
expression, all identical except for the string constant, which will bloat
your CIL.
But I just realised there is something else wrong here. What do you do with
exceptions? Exceptions from inside the tasks cannot be caught outside
without actually waiting on them (await, Wait, ContinueWith, accessing
Result, etc.).
try
{
new Action(async () => { var r = await SomethingAsync("a"); UpdateUI(r);
})();
new Action(async () => { var r = await SomethingAsync("b"); UpdateUI(r);
})();
new Action(async () => { var r = await SomethingAsync("c"); UpdateUI(r);
})();
}
catch (Oops)
{
// No Oops exceptions from SomethingAsync can be handled here.
// They will go straight to the synchronization context's "unhandled"
handler
// instead.
}
The neatest way to handle these exceptions is probably to await the tasks
directly, but then you're back to your original async/await code.
--
Thomas Koster