Dire che ho le seguenti definizioni delle classi:Le migliori pratiche sull'uso asincrona/attendono
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) =>
{
// Update progressbar
};
calculator.DoWork();
}
}
Se vorrei fare il lavoro fatto in DoWork()
, sulla forma, in modo asincrono potrei aggiungere un metodo (GetCalculationTask
) che restituisce un'attività utilizzando Task.Run()
e aggiunge un gestore di eventi asincrono vale a dire un pulsante (MethodOne
).
Per favore correggimi se ho torto, ma mi sembra che questa sarebbe l'unica opzione quando le classi ClassThatUsesACalculator
e Calculator
risiedono in una libreria che non possiedo.
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);
}
Nel caso faccio proprio la biblioteca penso che ci sono altre due opzioni, una delle quali molto simile al primo. Probabilmente a causa della mancanza della mia comprensione.
Creare un metodo su ClassThatUsesACalculator
che incapsula il metodo DoWork()
e quindi richiamarlo da un metodo asincrono nel modulo.
o,
incapsulare le
LongRunningCalculation()
sulla classeCalculator
con unTask.Run()
.public Task<CalculatorResult> CalculateAsync() { return Task.Run(() => { return LongRunningCalculation(); }); }
Creare un metodo asincrono sul
ClassThatUsesACalculator
le chiamate che attende il metodo appena creato.public async Task DoWorkAsync() { for (int i = 0; i < 10; i++) { var result = await calculator.CalculateAsync(); DoSomethingWithCalculationResult(result); DoLightWork(); OnProgressChanged(); } }
Creare un metodo asincrono sul modulo (
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(); }
Ora, a mio parere, l'ultima opzione sarebbe la migliore come vorrei rimanere più controllo. Ma forse sono lontana e vorrei avere l'opinione di qualcuno o dei suggerimenti su questo argomento, poiché posso solo trovare spiegazioni su come consumare asincrono, ma mai veramente su come costruire metodi che gli altri possano consumare.
La tua domanda è davvero lunga ed eccessivamente prolissa: potrebbe essere d'aiuto se la si restringe per spiegare concisamente ciò che si vuole sapere. A proposito, per cose veloci, 'async' non è veramente necessario. 'async' è ottimo per le attività di I/O come l'accesso a un file, database o servizio web. Ma il sovraccarico per l'esecuzione di bit rapidi di codice non I/O potrebbe effettivamente ridurre le prestazioni. – mason