Я попытался использовать метод SwitchTo сегодня, чтобы переключиться на поток графического интерфейса пользователя, и обнаружил, что пример, из которого я его поднял, не работает просто потому, что метода там нет.
Затем я нашел это объявление здесь:
Причина, по которой мы избавились от него, заключалась в том, что это было очень опасно. Альтернатива - связать свой код внутри TaskEx.Run ...
У меня простой вопрос: Почему это было опасно? К каким конкретным опасностям может привести его использование?
Обратите внимание, что я прочитал оставшуюся часть этого сообщения, поэтому я понимаю, что здесь есть технические ограничения. У меня все еще вопрос: если я знаю об этом, почему это опасно?
Я подумываю о повторной реализации вспомогательных методов, чтобы дать мне указанную функциональность, но если есть что-то принципиально сломанное, кроме того, что кто-то решил, что это опасно, я бы не стал этого делать.
В частности, очень наивно, вот как я бы рассмотрел реализацию требуемых методов:
public static class ContextSwitcher
{
public static ThreadPoolContextSwitcher SwitchToThreadPool()
{
return new ThreadPoolContextSwitcher();
}
public static SynchronizationContextSwitcher SwitchTo(this SynchronizationContext synchronizationContext)
{
return new SynchronizationContextSwitcher(synchronizationContext);
}
}
public class SynchronizationContextSwitcher : INotifyCompletion
{
private readonly SynchronizationContext _SynchronizationContext;
public SynchronizationContextSwitcher(SynchronizationContext synchronizationContext)
{
_SynchronizationContext = synchronizationContext;
}
public SynchronizationContextSwitcher GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get
{
return false;
}
}
public void OnCompleted(Action action)
{
_SynchronizationContext.Post(_ => action(), null);
}
public void GetResult()
{
}
}
public class ThreadPoolContextSwitcher : INotifyCompletion
{
public ThreadPoolContextSwitcher GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get
{
return false;
}
}
public void OnCompleted(Action action)
{
ThreadPool.QueueUserWorkItem(_ => action(), null);
}
public void GetResult()
{
}
}
Это позволило бы мне написать такой код:
public async void Test()
{
await ContextSwitcher.SwitchToThreadPool(); // ensure we're not bogging down the UI thread
// do some heavy processing
await _UIContext.SwitchTo(); // presumably saved from the main thread
// update UI with new data
}
await Task.Run(async ()=>{})
- не для того, чтобы избежать пустых опасностей, а просто потому, что мне кажется, что это легче читать. Тем не менее, я считаю, что ваше представление о том, как реализоватьSwitchTo()
, здраво. - person Cory Nelson   schedule 12.03.2013async ()=>{}
, требует дальнейшего изучения, спасибо! - person Lasse V. Karlsen   schedule 12.03.2013Send()
, а неPost()
, потому что, согласно этому сообщению в блоге, это будет означает, что дляDispatcherSynchronizationContext
именно потоки, не относящиеся к пользовательскому интерфейсу, переключатся на поток пользовательского интерфейса, а поток пользовательского интерфейса сохранит контекст. СPost()
, ожидание будет обходить диспетчер, испортить трассировку стека, даже если вы ожидаете в потоке пользовательского интерфейса. И для всех остальныхSynchronizationContexts
это все равно не имело бы значения. (Тогда они не будут меняться, что, я думаю, тоже нормально). - person John   schedule 25.06.2017