在Program.Main()中等待异步方法的正确方法是什么?

时间:2016-02-07 03:01:38

标签: c# winforms asynchronous

以下内容将始终挂起:

namespace WhyDoesThisAlwaysHappen {
    static class Program {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main( ) {
            Application.EnableVisualStyles( );
            Application.SetCompatibleTextRenderingDefault( false );
            new Form1( );
            DGApp.Start( ).DontBlock( ).GetAwaiter( ).Result( );
        }
    }

    static class Extensions {
        public static async Task DontBlock( this Task T ) {
            await T.ConfigureAwait( false );
        }

        public static async Task<T> DontBlock<T>( this Task<T> T2 ) {
            return await T2.ConfigureAwait( false );
        }
    }

    static class DGApp {
        public static async Task Start( ) {
            await RegistrationTables.Instance.Initialize( ).DontBlock( );
        }
    }

    class RegistrationTables {
        private static RegistrationTables _Instance = null;
        public static RegistrationTables Instance { get { return RegistrationTables._Instance ?? ( RegistrationTables._Instance = new RegistrationTables( ) ); } }
        private SQL SQLTool;

        public async Task Initialize( ) {
            await ( this.SQLTool = new SQL( new CancellationTokenSource( ).Token ) ).ReadConnectionFile( "Foo" ).DontBlock( );
        }
    }

    class SQL {
        private CancellationToken _CT;
        public SQL( CancellationToken CT ) {
            this._CT = CT;
        }

        public async Task ReadConnectionFile( string Foo ) {
            string[ ] ConnectionDetails = await FTP.ReadFile( Foo, this._CT ).DontBlock( );
        }
    }

    static class FTP {
        public static async Task<string[ ]> ReadFile( string Foo, CancellationToken CT ) {
            await Task.Delay( 1000 ).DontBlock( );
            return new string[ ] { };
        }
    }
}

Form1( )只不过是在创建新的WinForms项目时创建的默认空白表单。

我发现,如果我要将新的Form1( )注释掉它完全正常的行,但当我离开该行时,它会挂在最后的await Task.Delay( ... );

为什么会一直这样?从Program.Main( )调用异步方法的正确方法是什么?它甚至可能吗?

编辑1

请注意,无论DontBlock( )扩展程序是否存在(或不存在),都会始终如此。

1 个答案:

答案 0 :(得分:1)

您需要创建一个应用程序循环,在winforms世界中,意味着使用Application.Run。然后,该消息循环将处理发送给它的所有异步消息。如果你愿意,你当然可以创建自己的消息循环,但由于你使用的是winform应用程序,你可以使用它们。

  

为什么会这种情况继续发生?

因为您始终使用依赖于其他 UI消息的操作同步阻止UI线程,从而创建死锁。您不需要同步阻止此类操作,并且有一个实际上允许处理消息的消息循环。

  

请注意,无论DontBlock()扩展程序是否存在(或不存在),都会始终如此。

当然可以。这是因为您在调用DontBlock时阻止,并命名方法&#34; DontBlock&#34;不会阻止它。除了浪费一些CPU周期创建一个与其作为参数的任务功能相同的任务之外,您的DontBlock方法几乎没有任何作用。如果您只是删除了对该方法的所有调用,那么您的程序将具有相同的功能。