同期コンテキストを比較するにはどうすればよいですか?BeginInvokeを使用すると、同じディスパッチャが異なるSynchronizationContextを作成できるようです。2つの(等しくない)コンテキストにドリルダウンすると、ディスパッチャーのスレッド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?!?!?
}
たぶん、それらの2つを一緒に使用することはできません。私はこれが実際に機能することに気づきました:
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);
}
}
そしてこれを見てください:
「直接の発信者には完全な信頼が必要です。このメンバーは、部分的に信頼されているコードや透過的なコードでは使用できません。」:(