Почему не появляется "System.InvalidOperationException"?
Недавно начал изучать Thread и Invoke и столкнулся с проблемой.
Почему следующий код выполняется без Exception:
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 выполняется, ведь мы все же обращаемся к контролу который был создан в другом потоке.
И, кстати, если в DoStuff2 сам текст немного изменить, например на info from new thread2, то уже будет Exception. Это какая-то особенность языка, он проверяет что сам текст не меняется и не вызывает присваивание текста? И почему также выполняется без Exception button1.BackColor = Color.Red, здесь мы ведь тоже обращаемся к контролу?
Ответы (1 шт):
Свойства некоторых контролов не защищены от изменений из потоков, только и всего. Возможно это сделано в целях оптимизации, потому что на проверку контекста синхронизации все равно уходило бы какое-то время, возможно по каким-то другим причинам.
То есть обращение таким образом к Label допустимо, но целостность данных в свойстве Text - ваша ответственность, так как вероятные проблемы при конкурентном редактировании свойства этого контрола никуда не делись. .NET вам просто разрешает это сделать.
По сути исключения при обращении к контролам из стороннего потока берутся не из ниоткуда, а только там, где разработчики .NET эту проверку встроили, чтобы обезопасить нас от самых популярных ошибок при работе в условиях многопоточности.
В WPF есть пример, где подобное исключение возникает при использовании обычной коллекции - ObservableCollection, при использовании ее в контексте синхронизации UI. При попытке модифицировать коллекцию из стороннего потока выскочит NotSupportedException, причина - ровно та же, что и у вас в вопросе. А это ведь вообще не контрол.
Так что избавляйтесь от шаблона, что это некая особенность контролов - не давать себя менять из потоков, это просто такое решение разработчиков .NET, где добавить проверку, а где - нет.