Почему не появляется «System.InvalidOperationException»?

Извините за глупый вопрос, но только начал узнавать о Threads и Invoke. Почему этот код выполняется без каких-либо исключений:

private void button1_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(DoStuff1);
    thread.Name = "new thread";
    thread.Start();
}

private void DoStuff1()
{
    this.label1.Invoke((MethodInvoker)(() => label1.Text = "info from new thread"));
    button1.BackColor = Color.Red;
    DoStuff2();
}

private void DoStuff2()
{
    label1.Text = "info from new thread";
}

Почему тело метода DoStuff2 выполняется, несмотря на то, что мы пытаемся изменить управление, созданное UI-потоком, из совершенно другого потока. И кстати, если мы немного изменим метод DoStuff2, и изменим текст, например на info from new thread2, то появится Exception. Это какая-то спецификация языка, он сравнивает тексты и, если они совпадают, ничего не делает? И, кстати, почему этот код выполняется без Exception button1.BackColor = Color.Red, здесь мы тоже балуемся с управлением в UI-потоке.

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

canton7 17.12.2020 12:00

Настоящий вопрос заключается в том, почему вы используете необработанные потоки и Invoke, когда async/await и Task.Run доступны в течение 8 лет? Вы даже не упомянули, какой фреймворк используется. Может быть, просто возможно, изменение цвета не приводит к броску, потому что это не влияет на элемент управления, пока его не нужно перерисовывать. Изменение текста означает, что элемент управления должен измениться немедленно. Это может быть задокументировано или случайно. Хотя весь код плохой

Panagiotis Kanavos 17.12.2020 12:03

@PanagiotisKanavos спасибо за ваш ответ. Настоящий ответ - я только учусь. Я еще не использую его. Это просто тестовый код. Я нахожу интересное место в коде, и, поскольку я не смог найти документальный ответ на msdn и в любом другом месте, я решил спросить его здесь, потому что считаю это важным. Теперь я углублюсь и постараюсь улучшить качество своего кода. Спасибо за правильный путь.

Jam 17.12.2020 12:09

Документированный ответ для всех ОС, начиная с 1990-х годов, никогда не модифицирует пользовательский интерфейс из другого потока. Не только для Windows — Linux (в частности, оконные менеджеры) и MacOS имеют такое же ограничение. Некоторые фреймворки будут сбрасываться до того, как пользовательский интерфейс будет искажен, некоторые - нет. .NET вообще не жаловался до 4.0.

Panagiotis Kanavos 17.12.2020 12:11

Я предполагаю, что вы проводите тесты в приложении WinForms. Попробуйте добавить это при запуске вашей программы: Control.CheckForIllegalCrossThreadCalls = true;, чтобы увидеть, имеет ли это какое-то значение.

Theodor Zoulias 17.12.2020 13:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
190
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Резюмируя комментарии:

Обновление объектов пользовательского интерфейса из фонового потока всегда небезопасно:

Отладчик Visual Studio обнаруживает эти вызовы небезопасных потоков, вызывая InvalidOperationException с сообщением Недопустимая операция между потоками. Элемент управления "" доступен из потока, отличного от потока, в котором он был создан. InvalidOperationException всегда возникает для небезопасных вызовов между потоками во время отладки Visual Studio и может возникать во время выполнения приложения. Вы должны решить эту проблему, но вы можете отключить исключение, установив для свойства Control.CheckForIllegalCrossThreadCalls значение false.

От Делайте потокобезопасные вызовы к элементам управления Windows Forms. Большинство фреймворков пользовательского интерфейса, как правило, запрещают вызовы между потоками, поэтому это не уникально для оконных форм.

Правильный способ - убедиться, что вы обновляете пользовательский интерфейс только из основного потока. Шаблон async/await делает это довольно легко, если вы следуете общему шаблону и не делаете ничего странного.

private void button1_Click(object sender, EventArgs e){
    // Do async call
    var result = await SomeAsyncMethodCall();
    // Update the UI
    myTextbox.Text = result;
}

Другие вопросы по теме