C# 如何转换任务<;字节[]>;要在BackgroundWorker内部使用的字节[]?
我有以下方法:C# 如何转换任务<;字节[]>;要在BackgroundWorker内部使用的字节[]?,c#,.net,async-await,task,backgroundworker,C#,.net,Async Await,Task,Backgroundworker,我有以下方法: public async Task<byte[]> MyMethod(byte[] my_byte_array) { //modify my_byte_array ... return my_modified_byte_array; } 但随后出现一个错误无法将类型“System.Threading.Tasks.Task”隐式转换为“byte[]”。当我读到有关它的解决方案时,它指示将调用函数更改为asycn。但我不能成为as
public async Task<byte[]> MyMethod(byte[] my_byte_array)
{
//modify my_byte_array ...
return my_modified_byte_array;
}
但随后出现一个错误无法将类型“System.Threading.Tasks.Task”隐式转换为“byte[]”。当我读到有关它的解决方案时,它指示将调用函数更改为asycn。但我不能成为asycn的后台工作人员。这个问题不能解决吗?从BW转换到其他任务方法将花费我大量时间。您可以使事件处理程序异步。然后使用
wait
解析该值
private async void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//somewhere in BW
byte[] my_new_byte_array = await MyMethod(my_byte_array);
}
如果后台工作人员只工作几秒钟(不是分钟),考虑将完整的后台工作人员转换为异步方法。
如果有点依赖,你的backgroundworker会做什么:是因为计算而使用了大量的处理能力,还是主要是在等待外部进程完成,比如读取数据库、从internet获取项目、编写文件等等 在后面的例子中,您将看到backgroundworker使用了许多方法,这些方法可能也具有异步版本如果是这样的话,考虑把你的背景工作变成一个异步方法。< /P> 假设您的背景工作如下:
private async void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// get the input:
List<string> fileNames = (string)e.Argument;
List<int> processedProductIds = new List<int>();
// process the input
for (int i=0; i<fileNames.Count; ++i)
{
var products = ReadProductFile(fileNames[i]);
var productIds = AddProductsToDatabase(products);
processedProductIds.AddRange(productIds);
// report progress
var percentage = 100.0 * (double)i / (double)fileNames.Count;
backgroundWorker.ReportProgress(percentage, fileName);
}
// return output
e.Result = processedProductIds;
}
将DoWork更改为异步方法。您不必使用事件来报告进度:
public async Task<List<int>> DoWorkAsync(List<string> fileNames)
{
List<int> processedProductIds = new List<int>();
for (int i=0; i<fileNames.Count; ++i)
{
var products = await ReadProductFileAsync(fileNames[i]);
var productIds = await AddProductsToDatabaseAsync(products);
processedProductIds.AddRange(productIds);
// report progress
var percentage = 100.0 * (double)i / (double)fileNames.Count;
ReportProgress(percentage, fileName);
}
return processedProductIds;
}
所有的工作都是由同一条线完成的。不完全是这样,但是wait之后的线程具有相同的上下文,因此它可以像原始线程一样工作。因此,不需要互斥体、invokererequired等
启动backgroundworker的事件处理程序现在也是异步的
this.button1.Clicked += OnButtonStartProcessing_ClickedAsync;
private async void OnButtonStartProcessing_ClickedAsync(object sender, ...)
{
this.button1.Enabled = false;
this.progressBar1.Value = 0;
this.progressBar1.Visible = true;
List<string> fileNames = this.FetchFilesNamesToProcess();
List<int> processedIds = await ReadProductFilesAsync(fileNames);
this.UpdateProcessedIds(processedIds);
this.progressBar1.Visible = false;
this.button1.Enabled = true;
}
用法:
return await CalculateAsync(3, 4);
最后:如果你可以做一些有用的事情,而不是等待其他任务完成,那么不要等待:
// Fetch the customer, do not await yet:
Task<int> taskA = FetchCustmer();
// because you didn't await, you can continue:
int b = DoSomethingElse();
// now you need the result for taskA
int a = await TaskA;
return a+b;
//获取客户,不要等待:
任务taskA=FetchCustmer();
//因为您没有等待,所以可以继续:
int b=DoSomethingElse();
//现在需要taskA的结果
int a=等待任务a;
返回a+b;
这将标记BackgroundWorker为已完成。也许这就是OP需要的,也许不是,但不是马上obvious@Charlieface是的,调用ProgressChanged时出错。当代码在DoWork内调用ReportProgress时,我会遇到此错误:System.InvalidOperationException HResult=0x80131509 Message=此操作已对其调用OperationCompleted,并且进一步的调用是非法的。有什么补救办法吗?Anis的答案看起来很有趣,但与dovid的答案很相似,我不认为把这两种异步风格混为一谈是明智的。您不必转换所有代码来使用它,只需这一个工作流,即此特定BackgroundWorker
sDoWork
和RunWorkerCompleted
events@pnatk正确的解决方案可能是使任何事件启动后台工作程序async void
,然后在那里调用wait
您的MyMethod(my_byte_array)
。@在我的例子中,Llama BW是连续运行的,需要在每个do while(true)循环中调用MyMethod。一个按钮点击事件启动BW,需要在BW内部执行MyMethod的调用和返回,就像我的问题中一样。dovid的答案对我来说很有效,但我不知道为什么会落选。BackgroundWorker
之所以被创建,是因为没有语言支持异步代码来轻松编写异步代码。以前可以编写异步代码,现在使用async
-wait
编写异步代码要容易得多。顺便说一句,BackgroundWorker
是IMHO。不能处理异步工作负载只是它的缺点之一。我不知道为什么会得到负票。这对我来说很有效。我没有否决新冠病毒,但看到了它的一些缺点:@Llama如果我没有弄错的话,BackgroundWorker
无论如何都会创建一个专用的新线程。@dovid实际上BackgroundWorker
使用一个ThreadPool
线程。您可以通过在控制台中打印属性Thread.CurrentThread.IsThreadPoolThread
来确认它。
void UpdateProgress (int percentage, string fileName)
{
this.progressBar.Value = percentage;
this.ListBoxFileNames.Items.Add(fileName);
}
this.button1.Clicked += OnButtonStartProcessing_ClickedAsync;
private async void OnButtonStartProcessing_ClickedAsync(object sender, ...)
{
this.button1.Enabled = false;
this.progressBar1.Value = 0;
this.progressBar1.Visible = true;
List<string> fileNames = this.FetchFilesNamesToProcess();
List<int> processedIds = await ReadProductFilesAsync(fileNames);
this.UpdateProcessedIds(processedIds);
this.progressBar1.Visible = false;
this.button1.Enabled = true;
}
// Warning, this procedure will take 5 seconds!
private int Calculate(int x, int y) {...}
private async Task<int> CalculateAsync(int x, int y)
{
await Task.Run( () => this.Calculate(x, y));
}
return await CalculateAsync(3, 4);
// Fetch the customer, do not await yet:
Task<int> taskA = FetchCustmer();
// because you didn't await, you can continue:
int b = DoSomethingElse();
// now you need the result for taskA
int a = await TaskA;
return a+b;