如何比较 SynchronizationContext?看来同一个Dispatcher在使用BeginInvoke时可以创建不同的SynchronizationContext。当我深入研究两个(不相等的)上下文时,我发现调度程序线程 ID 相同,但它们彼此并不相等。
public partial class MainWindow : Window
{
private SynchronizationContext contexta;
private SynchronizationContext contextb;
private SynchronizationContext contextc;
private SynchronizationContext contextd;
public MainWindow()
{
InitializeComponent();
contexta = SynchronizationContext.Current;
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
contextb = SynchronizationContext.Current;
Dispatcher.Invoke(() =>
{
contextc = SynchronizationContext.Current;
});
Dispatcher.BeginInvoke(new Action(() =>
{
contextd = SynchronizationContext.Current;
}));
Debug.Assert(contexta != contextb);
Debug.Assert(contexta == contextc); // fails... why?!?!?
Debug.Assert(contexta == contextd); // fails... why?!?!?
Debug.Assert(contextc == contextd); // fails... why?!?!?
}
或许两者不能同时使用。我注意到这确实有效:
contexta.Send(new SendOrPostCallback((s) =>
{
contexte = SynchronizationContext.Current;
}), null);
Update但奇怪的是,它并不总是有效。
public override void AddRange(IEnumerable<T> items)
{
if (SynchronizationContext.Current == _context)
{
base.AddRange(items);
}
else
{
_context.Send(new SendOrPostCallback((state) =>
{
AddRange(state as IEnumerable<T>);
}), items);
}
}
例如,永远不会获得匹配的 _context 并永远持续下去。尽管不应该。后一个示例中的线程实际上最终是相同的,并且有一个上下文,但它是不同的。
Update2好吧,我已经开始工作了,但我真的感觉不舒服。显然,当您发布或发送时,您的任务是从正确的线程运行的,但如果您不是来自 UI,则似乎会生成一个新的 SynchronizationContext。
public override void AddRange(IEnumerable<T> items)
{
if (SynchronizationContext.Current == _context)
{
base.AddRange(items);
}
else
{
_context.Post(new SendOrPostCallback((state) =>
{
if (SynchronizationContext.Current != _context)
SynchronizationContext.SetSynchronizationContext(_context); // called every time.. strange
AddRange(items);
}), null);
}
}
看看这个:
“需要直接调用者完全信任。部分信任或透明的代码不能使用此成员。” :(