Say I have the following class definitions:
public class Calculator { public CalculatorResult Calculate() { return LongRunningCalculation(); } private CalculatorResult LongRunningCalculation() { return new CalculatorResult(0.00); } } public class ClassThatUsesACalculator { private readonly Calculator calculator; public ClassThatUsesACalculator() { this.calculator = new Calculator(); } public void DoWork() { for (int i = 0; i < 10; i++) { var result = calculator.Calculate(); DoSomethingWithCalculationResult(result); DoLightWork(); OnProgressChanged(); } } } public partial class Form : Form { public Form() { InitializeComponent(); } private void Method(object sender, EventArgs e) { DoWork(); } private void DoWork() { var calculator = new ClassThatUsesACalculator(); calculator.ProgressChanged += (s, e) => {
If I wanted to do the work done in DoWork() in a form asynchronously, I could add a method ( GetCalculationTask ) that returns the task using Task.Run() and adds an asynchronous event handler, i.e. for the ( MethodOne ) button.
Please correct me if I am wrong, but it seems to me that this will be the only option when the ClassThatUsesACalculator and Calculator classes are in a library that I do not own.
private Task GetCalculationTask(IProgress<CalculatorProgress> progress) { var calculator = new ClassThatUsesACalculator(); calculator.ProgressChanged += (s, e) => { progress.Report(new CalculatorProgress(0)); }; return Task.Run(() => { calculator.DoWork(); }); } private async void MethodOne(object sender, EventArgs e) { IProgress<CalculatorProgress> progress = new Progress<CalculatorProgress> (UpdateProgressBar); await GetCalculationTask(progress); }
In case I have a library, I think there are two more options, one of which is very similar to the first. Perhaps due to a lack of my own understanding.
Create a method on the ClassThatUsesACalculator that encapsulates the DoWork() method, and then call it from the asynchronous method on the form.
or,
Encapsulate LongRunningCalculation() in the Calculator class using Task.Run() .
public Task<CalculatorResult> CalculateAsync() { return Task.Run(() => { return LongRunningCalculation(); }); }
Create an asynchronous method for the ClassThatUsesACalculator calls waiting for the newly created method.
public async Task DoWorkAsync() { for (int i = 0; i < 10; i++) { var result = await calculator.CalculateAsync(); DoSomethingWithCalculationResult(result); DoLightWork(); OnProgressChanged(); } }
Create an asynchronous method in the form ( MethodThree )
private async void MethodThree(object sender, EventArgs e) { IProgress<CalculatorProgress> progress = new Progress<CalculatorProgress>(UpdateProgressBar); var calculator = new ClassThatUsesACalculator(); calculator.ProgressChanged += (s, args) => { progress.Report(new CalculatorProgress(0)); }; await calculator.DoWorkAsync(); }
Now, in my opinion, the latter option would be better, since I would have remained more in control. But maybe I left, and I would like someone to think or point out this, since I can only find explanations on how to consume asynchronous mode, but never know how to create methods for consumption by others.
source share