完了すると、一般的な引数で呼び出されるコールバックを受け取るアクションがありますAction<Action<T>>
。アクションの開始時にビジー状態のスピナーを表示し、コールバックの呼び出し時にスピナーを取り除きたいので、それを行うための簡単なユーティリティを作成しました。私が抱えている問題は、ユーザーがコールバックが元の呼び出しスレッドで実行されることを期待しているが、常にそうであるとは限らないことです。ほとんどの場合、単体テスト (nUnit) では完全に機能しますが、アプリケーションが実際に実行されているとき (WPF、.Net 4) の一部の呼び出しでは機能しません。
ここに私が持っているものの関連部分があります
void WrapAsyncCallbackPattern<T>(Action<T> callback, Action<Action<T>> actionToRun)
{
var subject = new AsyncSubject<T>();
try
{
actionToRun(
result =>
{
subject.OnNext(result);
subject.OnCompleted();
});
}
catch (Exception ex)
{
subject.OnError(ex);
}
subject
.ObserveOn(Scheduler.CurrentThread)
.Subscribe(callback, OnError);
}
callback
サブスクライブしている (そして宣言されている) スレッドで実行したいのですsubject
が、確実に実行されないようです。私はばかげたことをしていると思います。それは何ですか?
編集:ユニットテストコードを追加
private readonly TimeSpan m_WaitTime = TimeSpan.FromSeconds(1);
[Test]
public void WrapAsyncCallbackPattern_WithActionOnDifferentThread_CallsCallbackOnSameThread()
{
var awaiter = new AutoResetEvent(false);
bool callbackRan = false;
int callingThreadId = Thread.CurrentThread.ManagedThreadId;
int callbackThreadId = int.MinValue;
int actionThreadId = int.MinValue;
BackgroundOperation.WrapAsyncCallbackPattern<int>(
_ =>
{
callbackRan = true;
callbackThreadId = Thread.CurrentThread.ManagedThreadId;
awaiter.Set();
},
cb => ThreadPool.QueueUserWorkItem(
_ =>
{
actionThreadId = Thread.CurrentThread.ManagedThreadId;
cb(0);
}));
var errorInfo = string.Format("\r\nCalling thread = {0}; Action thread = {1}; Callback thread = {2}", callingThreadId, actionThreadId, callbackThreadId);
Assert.IsTrue(awaiter.WaitOne(m_WaitTime));
Assert.IsTrue(callbackRan);
Assert.AreNotEqual(callingThreadId, actionThreadId, "Action needs to be run on a different thread for this test." + errorInfo);
Assert.AreNotEqual(actionThreadId, callbackThreadId, "Callback should not be run on action thread." + errorInfo);
Assert.AreEqual(callingThreadId, callbackThreadId, "Callback should be run on calling thread." + errorInfo);
}