В чем разница между Invoking и BeginInvoking MessageBox?

В форме сравните

BeginInvoke (new Action (() => {
    MessageBox.Show ());
}));

с

Invoke (new Action (() => {
    MessageBox.Show ());
}));

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

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

Единственное различие заключается в том, что Invoke фактически вызывается мгновенно, а BeginInvoke занимает (очень короткое) время, пока код не будет запущен. Этого следует ожидать.

Ответ 1

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

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

Чтобы увидеть разницу, попробуйте следующий код:

BeginInvoke(new Action(()=>Console.WriteLine("BeginInvoke")));
Console.WriteLine("AfterBeginInvokeCalled");

Invoke(new Action(()=>Console.WriteLine("Invoke")));
Console.WriteLine("AfterInvokeCalled");

Вы должны увидеть результат, похожий на следующий, где текст "BeginInvoke" задерживается из-за его асинхронного выполнения:

AfterBeginInvokeCalled
   Призовите
   AfterInvokeCalled
   BeginInvoke

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

Ответ 2

Саймон на самом деле не ошибается.

BeginInvoke походит на отправку сообщения в поток пользовательского интерфейса и говорит: "Сделайте это, как только получите шанс".

Invoke - это как сказать: "Сделайте это прямо сейчас. Я подожду."

Разъяснение: только потому, что вы расскажите поток пользовательского интерфейса, "сделайте это прямо сейчас", это не значит, что вы являетесь Богом потока пользовательского интерфейса и можете заставить его отказаться от всего, что он делает. В основном, ключевые слова в приведенном выше заявлении: "Я подожду".

Дело в том, что в вашем примере кода сообщение, которое вы отправляете в поток пользовательского интерфейса, это: call MessageBox.Show. Угадай, что? Это будет блокировать поток пользовательского интерфейса в любом случае.

Если вы хотите заметить асинхронное поведение BeginInvoke, вызовите его из отдельного потока, поместите точку останова после вызова BeginInvoke в свой код и обратите внимание, что точка останова попадает даже тогда, когда отображается окно сообщения (и пользовательский интерфейс заблокирован). Если вы вызываете Invoke, код не будет продолжаться до тех пор, пока пользователь не отклонит окно сообщения.

Ответ 3

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

Итак, диалоговое окно всегда зависает от графического интерфейса. Но разница между begin invoke и invoke должна быть ясна:

Invoke ожидает, что вызванный метод вернется BeginInvoke не делает.

Ответ 4

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

Почему вы хотите сначала обернуть вызовы MessageBox() в Invoke/BeginOnvoke?

В этой ситуации просто нет пользы в использовании BeginInvoke или Invoke, как объяснил Джефф.

Похоже, вы сбиты с толку между использованием Invoke/BeginInvoke в форме/управлении Windows в многопоточной ситуации и использованием Invoke/BeginInvoke на экземпляре делегата (например, Asynchornous Programming Model).

Это легко сделать, поскольку имена, очевидно, идентичны, однако сценарии, которые вы использовали бы их, и их поведение различны.

Книга CLR Via С# дает хорошее объяснение обоих типов Invoke/BeginInvoke.

Ответ 5

Для MessageBox.Show вопрос в основном не имеет значения.

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

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