C# noob here, coming from experience in other languages. (Most notably Java).
I'm looking at this question's code. It's a standard WinForms C# project in VS 2013:
drop a button and a textbox on the form and use this code:
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
.ContinueWith(t => DelayedAdd(t.Result, 20))
.ContinueWith(t => DelayedAdd(t.Result, 30))
.ContinueWith(t => DelayedAdd(t.Result, 50))
.ContinueWith(t => textBox1.Text = t.Result.ToString(),
TaskScheduler.FromCurrentSynchronizationContext());
}
private int DelayedAdd(int a, int b)
{
Thread.Sleep(500);
return a + b;
}
Press the button, wait 2 seconds for the four DelayedAdd
calls to complete, and the result (115) is displayed in the text box. How can I get the result displayed on the text box after every DelayedAdd
call?
I tried to shove the final continuation between each call,
Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
.ContinueWith(t => textBox1.Text = t.Result.ToString(),
TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(t => DelayedAdd(t.Result, 20))
.ContinueWith(t => textBox1.Text = t.Result.ToString(),
TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(t => DelayedAdd(t.Result, 30))
.ContinueWith(t => textBox1.Text = t.Result.ToString(),
TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(t => DelayedAdd(t.Result, 50))
.ContinueWith(t => textBox1.Text = t.Result.ToString(),
TaskScheduler.FromCurrentSynchronizationContext());
but that fails, I'm guessing because the continuations I inserted don't return the integer result t
. I'm such a C# noob that I don't even know how to fix that, let alone do this in an idiomatic way.
I'd just change DelayedAdd
method:
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
.ContinueWith(t => DelayedAdd(t.Result, 20))
.ContinueWith(t => DelayedAdd(t.Result, 30))
.ContinueWith(t => DelayedAdd(t.Result, 50));
}
private int DelayedAdd(int a, int b)
{
if (textBox1.InvokeRequired)
{
textBox1.BeginInvoke((Action)(() => textBox1.Text = (a + b).ToString()));
}
Thread.Sleep(500);
return a + b;
}
Got it! If anyone has better/more interesting alternatives, please answer.
First I tried a multiline lambda in place of the erroneous continuations from my question:
.ContinueWith(t => {
textBox1.Text = t.Result.ToString();
return t.Result;
},
TaskScheduler.FromCurrentSynchronizationContext());
}
That's a tad verbose and repetitive, so I DRYed it up:
private void button1_Click(object sender, EventArgs e)
{
// SCHEDULING LOGIC
Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
.ContinueWith(t => UpdateText(t.Result),
TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(t => DelayedAdd(t.Result, 20))
.ContinueWith(t => UpdateText(t.Result),
TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(t => DelayedAdd(t.Result, 30))
.ContinueWith(t => UpdateText(t.Result),
TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(t => DelayedAdd(t.Result, 50))
.ContinueWith(t => UpdateText(t.Result),
TaskScheduler.FromCurrentSynchronizationContext());
}
private int UpdateText(int i)
{
// UI LOGIC
textBox1.Text = i.ToString();
return i;
}
private int DelayedAdd(int a, int b)
{
// PROCESS LOGIC
Thread.Sleep(500);
return a + b;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With