WinForms 异步加载任务未完成
WinForms Async Load Task Does Not Complete
我正在使用 .NET Framework v4.7.2。我在下面有原始代码的简化版本。
在我最初的问题中,Form_Load()
处理程序过早结束,所以我决定将 Form_Load()
处理程序中的所有内容包装在 Task
中,然后在 Form_Show()
处理程序(在 Form_Load()
之后触发 )提取我在 Task
中异步加载的数据。我关心的数据是 stringArray
出来的 null
.
显然,我更愿意弄清楚 为什么 Form_Load()
提前结束,但我没有运气。
我知道我在这里苦苦挣扎,可能遗漏了一些基本概念。我觉得如果我能理解为什么stringArray
是null
,我就会理解为什么我原来的Form_Load()
提前结束了。 formLoadTask
的Status
属性是RanToCompletion
那么stringArray
怎么会是null
呢?
请记住这是真实代码的简化版本。
谢谢
interface IRetriever
{
Task<String[]> GetStringArray();
}
class Retriever : IRetriever
{
public async Task<string[]> GetStringArray()
{
return await Task.FromResult(new string[] { "More", "Larry", "Curly", });
}
}
static class Director
{
internal static async Task<IRetriever> CreateRetriever()
{
return await Task<IRetriever>.Factory.StartNew(() =>
{
// Simulate some I/O bound waiting...
Thread.Sleep(5000);
return new Retriever();
});
}
}
public partial class Form1 : Form
{
private static String[] stringArray;
private static IRetriever retriever;
internal Task formLoadTask;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
formLoadTask = Task.Factory.StartNew(async () =>
{
retriever = await Director.CreateRetriever();
stringArray = await retriever.GetStringArray();
});
}
private void Form1_Shown(object sender, EventArgs e)
{
// I know I am tying up the UI thread here. This is just an example.
formLoadTask.Wait();
// At this point the formLoadTask is finished, so shouldn't the stringArray be populated?
// The next line throws a NullReferenceException because stringArray is null.
// Why??
System.Diagnostics.Debug.WriteLine(stringArray.Length);
}
}
StartNew
无法识别您的异步委托。它把它当作一个没有人最终等待的 Func<Task>
。您存储在 formLoadTask
中的任务只是启动任务的任务,而不是任务本身。
您可以解包任务或使用更现代的 Task.Run
,它可以正确处理异步委托。
formLoadTask = Task.Factory.StartNew(async () =>
{
retriever = await Director.CreateRetriever();
stringArray = await retriever.GetStringArray();
}).Unwrap();
或(首选):
formLoadTask = Task.Run(async () =>
{
retriever = await Director.CreateRetriever();
stringArray = await retriever.GetStringArray();
});
我正在使用 .NET Framework v4.7.2。我在下面有原始代码的简化版本。
在我最初的问题中,Form_Load()
处理程序过早结束,所以我决定将 Form_Load()
处理程序中的所有内容包装在 Task
中,然后在 Form_Show()
处理程序(在 Form_Load()
之后触发 )提取我在 Task
中异步加载的数据。我关心的数据是 stringArray
出来的 null
.
显然,我更愿意弄清楚 为什么 Form_Load()
提前结束,但我没有运气。
我知道我在这里苦苦挣扎,可能遗漏了一些基本概念。我觉得如果我能理解为什么stringArray
是null
,我就会理解为什么我原来的Form_Load()
提前结束了。 formLoadTask
的Status
属性是RanToCompletion
那么stringArray
怎么会是null
呢?
请记住这是真实代码的简化版本。
谢谢
interface IRetriever
{
Task<String[]> GetStringArray();
}
class Retriever : IRetriever
{
public async Task<string[]> GetStringArray()
{
return await Task.FromResult(new string[] { "More", "Larry", "Curly", });
}
}
static class Director
{
internal static async Task<IRetriever> CreateRetriever()
{
return await Task<IRetriever>.Factory.StartNew(() =>
{
// Simulate some I/O bound waiting...
Thread.Sleep(5000);
return new Retriever();
});
}
}
public partial class Form1 : Form
{
private static String[] stringArray;
private static IRetriever retriever;
internal Task formLoadTask;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
formLoadTask = Task.Factory.StartNew(async () =>
{
retriever = await Director.CreateRetriever();
stringArray = await retriever.GetStringArray();
});
}
private void Form1_Shown(object sender, EventArgs e)
{
// I know I am tying up the UI thread here. This is just an example.
formLoadTask.Wait();
// At this point the formLoadTask is finished, so shouldn't the stringArray be populated?
// The next line throws a NullReferenceException because stringArray is null.
// Why??
System.Diagnostics.Debug.WriteLine(stringArray.Length);
}
}
StartNew
无法识别您的异步委托。它把它当作一个没有人最终等待的 Func<Task>
。您存储在 formLoadTask
中的任务只是启动任务的任务,而不是任务本身。
您可以解包任务或使用更现代的 Task.Run
,它可以正确处理异步委托。
formLoadTask = Task.Factory.StartNew(async () =>
{
retriever = await Director.CreateRetriever();
stringArray = await retriever.GetStringArray();
}).Unwrap();
或(首选):
formLoadTask = Task.Run(async () =>
{
retriever = await Director.CreateRetriever();
stringArray = await retriever.GetStringArray();
});