我有一个Windows窗体应用程序。
现在我想使用async
方法。
从C#7.1开始,我可以使用async Main
方法:
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7-1
但是,现在我的STAThread
属性被忽略,我的应用程序在MTA中运行。这是设计还是我可以强制我的应用程序再次以STA模式运行?
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static async Task Main(string[] args)
{
// returns MTA
Console.WriteLine("{0}", Thread.CurrentThread.ApartmentState);
}
答案 0 :(得分:3)
STA是您承诺单个线程将运行Windows消息泵(通常隐藏在Application.Run()
调用之后)的版本。当你的线程没有被占用时,你将在你的线程上运行消息泵。
async
方法是一种方法,当它没有更好的事情要做时,会释放它的线程以便做其他事情。
我无法将这两个概念对齐。如果你想要STA,你想要保持该线程和泵消息。所以使用async main
在那里没有意义。
在这种特殊情况下(各种初始化步骤可能会受益await
后跟Application.Run
我会使用async Main
而不使用 {{1}然后我将显式创建一个STA线程,专门用于运行windows消息循环。
没有规则你的程序中的第一个线程必须是/一个STA线程,我认为这提供了最干净的分离。如果您的STAThread
没有其他有用的工作要做,您可能希望在async Main
和消息循环运行线程之间共享TaskCompletionSource
,然后在Main
返回后发出完成信号
答案 1 :(得分:2)
Application.Run()
不适用于STAThread
。
问题在于,将async main
转换为“普通”async main
的代码不会复制该属性。
以下是more information具体关于未复制的属性。
在some of the discussion中,他们指的是使用SingleThreadedSynchronizationContext
来允许在STA线程中使用异步代码。
答案 2 :(得分:2)
我知道这很老了,但是达米安(Damien)的回答和随后的评论对我的问题有所帮助。我有一个控制台应用程序,其中需要调用async
方法,在某些时候可能需要STA执行才能使用OpenFileDialog
。
这是我得到的代码,以防它对他人(或对我未来的自我有帮助)。
1。创建用于将线程作为STA运行的扩展方法
public static class Extensions
{
public static void RunSTA(this Thread thread)
{
thread.SetApartmentState(ApartmentState.STA); // Configure for STA
thread.Start(); // Start running STA thread for action
thread.Join(); // Sync back to running thread
}
}
2。使用async main
到应用程序方法(没有await
属性)创建了[STAThread]
方法。
class Program
{
static async Task Main(string[] args)
{
await App.Get().Run(args);
}
}
3。使用扩展方法将OpenFileDialog
呼叫与STA打包
public string[] GetFilesFromDialog(string filter, bool? restoreDirectory = true, bool? allowMultiSelect = true)
{
var results = new string[] { };
new Thread(() =>
{
using (var dialog = new OpenFileDialog())
{
dialog.Filter = filter;
dialog.RestoreDirectory = restoreDirectory ?? true;
dialog.Multiselect = allowMultiSelect ?? true;
if (dialog.ShowDialog() != DialogResult.OK)
return; // Nothing selected
results = dialog.FileNames;
}
}).RunSTA();
return results;
}