如何比较 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);
更新但奇怪的是,它并不总是有效。
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);
}
}
看看这个:
“需要直接调用者完全信任。部分信任或透明代码不能使用此成员。” :(