Await Task зависает при создании нового экземпляра формы перед запуском задачи - PullRequest
0 голосов
/ 01 марта 2019

Мой код await зависает, если я запускаю создание нового экземпляра формы перед запуском кода await.

Если я прокомментирую строку Form frm = new Form();, код будет работать правильно, в противном случае он будет зависать в коде await Task.Delay(2000);.

Другим решением является создание нового экземпляра формы с помощью Task.Run(закомментированная строка в моем примере кода).Я понятия не имею, почему это работает, и не знаю, нормально ли создавать новый экземпляр формы в подпотоке.

Вот простой пример кода, чтобы повторить проблему.У кого-нибудь есть идея, почему это происходит?

using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ConsoleApp1
{
    class Program
    {
        public async static Task Main(string[] args)
        {
            //Form frm = await Task.Run( () => new Form());
            Form frm = new Form();
            await Delay();         
        }

        public static async Task Delay()
        {
            await Task.Delay(2000);
        }
    }
}

Извините за путаницу.Добавлен реальный код, который я пишу, который на самом деле является кодом модульного теста.

    public async Task TestFrmLoginGen1()
    {
        IFrmLogin frmLogin;
        frmLogin = await Task.Run(() => new FrmLogin());
        //frmLogin = new FrmLogin();

        FrmLoginPresenter loginPresenter = new FrmLoginPresenter(frmLogin);
        await  loginPresenter.LoginAsync();
    }

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

Мой код await зависает, если я запускаю команду создания нового экземпляра формы перед запуском кода await.

Ну, для этого есть ряд причин.

  1. Ваше приложение на самом деле является консольным приложением и , а не a WinForms .Вы пытаетесь отобразить графический интерфейс в консольном приложении, который обычно невозможен

  2. Консольные приложения по умолчанию имеют значение MTA, а не STA.STA является обязательным для всех приложений с графическим интерфейсом пользователя

  3. Консольные приложения не обрабатывают Windows Message Pump в отличие от, скажем, собственных окон илиприложение WinForms

Конечно, вы можете добавить насос сообщений в консольное приложение;форсировать поток STA, но зачем вам, когда в Visual Studio есть совершенно хороший мастер WinForms?

Я комментирую строку Form frm = new Form ();код будет работать правильно

Я действительно сомневаюсь в этом.У вас может быть окно , появляется , но оно, безусловно, не будет интерактивным .Если насос сообщений не обработан, окно не будет рисовать (включая рисование после того, как окно, которое было перед ним, было удалено).Нажатие кнопок и меню будет без ответа . Таймеры будут неработоспособны .

Наконец, не пытайтесь создать графический интерфейс через поток и / или Task, так как у вас мало контроля над STA.Все это должно быть сделано из основного потока приложения, который должен быть STA, как уже упоминалось.Существует небольшая причина для нескольких STA с.

В заключение, мало смысла использовать async/await при создании окна.

0 голосов
/ 01 марта 2019

Другие ответы о том, что вы не должны создавать формы внутри консольного приложения или модульного теста, абсолютно верны.

Из вашего обновленного кода похоже, что кто-то уже столкнулся с проблемой созданияЯ уверен, что вы можете выполнить модульное тестирование своего докладчика без необходимости создания экземпляра формы: конструктор FrmLoginPresenter принимает IFrmLogin, что, как я предполагаю, является интерфейсом, реализованным FrmLogin.Эта абстракция существует, чтобы позволить вам выполнить юнит-тестирование FrmLoginPresenter без необходимости создания фактического FrmLogin.

. То, что вы хотите сделать, - это создать фиктивную реализацию IFrmLogin.Это может быть обычный класс, который вы пишете сами, который реализует IFrmLogin (он может уже существовать в вашем наборе тестов), или он может использовать библиотеку насмешек, такую ​​как Moq или Rhino Mocks.

Затем вы передаете свой макетреализация к конструктору FrmLoginPresenter.

В конечном счете, похоже, что тот, кто спроектировал ваше приложение, уже задумывался о том, как его следует тестировать модулем.Вам, вероятно, следует пойти и поговорить с ними, чтобы получить полную картину их намерений.

0 голосов
/ 01 марта 2019

Ваш код никогда не вызывает Application.Run () для запуска цикла сообщений приложения.

Когда вы используете await, продолжение может быть отправлено в цикл сообщений в зависимости от контекста.Как только вы создаете форму, вы находитесь в таком контексте, и вы должны убедиться, что цикл сообщений действительно выполняется.

Бит кода инициализации приложения WinForms, где обычно вызывается Application.Run (), равенне очень хорошее место для использования async / await.

...