У ньому зберігається постачальник синхронізації - клас, похідний від SynchronizationContext. У цьому випадку, ймовірно, це буде екземпляр WindowsFormsSynchronizationContext. Цей клас використовує методи Control.Invoke () та Control.BeginInvoke () для реалізації методів Send () та Post (). Або це може бути DispatcherSynchronizationContext, він використовує Dispatcher.Invoke () та BeginInvoke (). У програмі Winforms або WPF цей постачальник автоматично встановлюється, як тільки ви створюєте вікно.
Коли ви запускаєте код на іншому потоці, як, наприклад, нитка пулу потоків, що використовується у фрагменті, ви повинні бути обережними, щоб ви не використовували безпосередньо об'єкти, які не є безпечними для потоку. Як і будь-який об’єкт інтерфейсу користувача, ви повинні оновити властивість TextBox.Text з потоку, який створив TextBox. Метод Post () гарантує, що ціль делегата працює на цьому потоці.
Слідкуйте за тим, що цей фрагмент є трохи небезпечним, він буде працювати правильно лише тоді, коли ви викликаєте його з потоку інтерфейсу користувача. СинхронізаціяContext.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, ви все одно залишите це до ключових слів асинхронізації / очікування C # або TaskScheduler.FromCurrentSynchronizationContext (), щоб зробити це за вас. Але зауважте, що вони все ще неправильно поводяться так, як робить фрагмент, коли ви використовуєте їх у неправильній нитці з точно тієї ж причини. Тут дуже поширене питання, додатковий рівень абстракції є корисним, але ускладнює з'ясування, чому вони не працюють правильно. Сподіваємось, книга також говорить вам, коли її не використовувати :)