В нем хранится поставщик синхронизации, класс, производный от SynchronizationContext. В этом случае это, вероятно, будет экземпляр WindowsFormsSynchronizationContext. Этот класс использует методы Control.Invoke () и Control.BeginInvoke () для реализации методов Send () и Post (). Или это может быть DispatcherSynchronizationContext, он использует Dispatcher.Invoke () и BeginInvoke (). В приложении Winforms или WPF этот провайдер устанавливается автоматически, как только вы создаете окно.
Когда вы запускаете код в другом потоке, например поток пула потоков, используемый во фрагменте, вы должны быть осторожны, чтобы напрямую не использовать объекты, небезопасные для потоков. Как и любой объект пользовательского интерфейса, вы должны обновить свойство TextBox.Text из потока, создавшего TextBox. Метод Post () гарантирует, что целевой делегат работает в этом потоке.
Помните, что этот фрагмент немного опасен, он будет работать правильно только тогда, когда вы вызовете его из потока пользовательского интерфейса. SynchronizationContext.Current имеет разные значения в разных потоках. Только поток пользовательского интерфейса имеет полезное значение. И это причина, по которой код должен был его скопировать. Более читаемый и безопасный способ сделать это в приложении Winforms:
ThreadPool.QueueUserWorkItem(delegate {
string text = File.ReadAllText(@"c:\temp\log.txt");
myTextBox.BeginInvoke(new Action(() => {
myTextBox.Text = text;
}));
});
Это имеет то преимущество, что он работает при вызове из любого потока. Преимущество использования SynchronizationContext.Current заключается в том, что он по-прежнему работает независимо от того, используется ли код в Winforms или WPF, это имеет значение в библиотеке. Это, конечно, не лучший пример такого кода, вы всегда знаете, какой у вас TextBox, поэтому вы всегда знаете, использовать ли Control.BeginInvoke или Dispatcher.BeginInvoke. На самом деле использование SynchronizationContext.Current не так уж часто.
Книга пытается научить вас многопоточности, поэтому использовать этот ошибочный пример - нормально. В реальной жизни в тех немногих случаях, когда вы могли бы рассмотреть возможность использования SynchronizationContext.Current, вы все равно оставите это на усмотрение ключевых слов async / await C # или TaskScheduler.FromCurrentSynchronizationContext (), чтобы сделать это за вас. Но обратите внимание, что они по-прежнему ведут себя плохо, как фрагмент, когда вы используете их не в том потоке, по той же причине. Очень распространенный вопрос здесь: дополнительный уровень абстракции полезен, но затрудняет понимание, почему они не работают правильно. Надеюсь, книга также подскажет, когда ее не использовать :)