当使用Observable.Interval
时,我得到了几次导致应用程序崩溃的以下异常(该异常只能在事件查看器中找到-错误来源:.NET Runtime)
Application: RxPlayground.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.ArgumentNullException
Stack:
at System.Reactive.Concurrency.AsyncLock.Wait(System.Action)
at System.Reactive.Concurrency.DefaultScheduler+<>c__DisplayClass9`1[[System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].<SchedulePeriodic>b__6()
at System.Reactive.Concurrency.ConcurrencyAbstractionLayerImpl+PeriodicTimer.Tick(System.Object)
at System.Threading.TimerQueueTimer.CallCallbackInContext(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.TimerQueueTimer.CallCallback()
at System.Threading.TimerQueueTimer.Fire()
at System.Threading.TimerQueue.FireNextTimers()
at System.Threading.TimerQueue.AppDomainTimerCallback()
你在使用响应式扩展时遇到过这样的问题吗?你知道可能是什么原因吗?
下面是一些可能导致问题的代码(但也许不是,因为我无法复制它…):
static void Main(string[] args)
{
var subscriptions = SubscribeToObservables().Take(10000).ToArray();
Console.WriteLine("BEGIN. Click Enter to Dispose...");
Console.ReadLine();
Console.WriteLine("DISPOSING");
foreach (var subscription in subscriptions)
{
subscription.Dispose();
}
Console.WriteLine("DISPOSED. Click Enter to finish...");
Console.ReadLine();
Console.WriteLine("END");
}
private static IEnumerable<IDisposable> SubscribeToObservables()
{
var x = Observable.Interval(TimeSpan.FromSeconds(1)).Select(n =>
{
//Thread.Sleep(TimeSpan.FromMinutes(1));
return n;
});
var sub = x.Subscribe(
n =>
{
Thread.Sleep(TimeSpan.FromMinutes(1));
Console.WriteLine(n);
});
yield return sub;
}
编辑:我已经检查了AsyncLock
类和它的所有引用(https://github.com/Reactive-Extensions/Rx.NET/blob/master/Rx.NET/Source/System.Reactive.Core/Reactive/Concurrency/AsyncLock.cs),我看不到任何可能性,动作委托可能是空的!在出现异常的情况下,我们可以从堆栈跟踪中看到Wait是从以下代码(https://github.com/Reactive-Extensions/Rx.NET/blob/master/Rx.NET/Source/System.Reactive.Core/Reactive/Concurrency/DefaultScheduler.cs):
public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)
{
if (period < TimeSpan.Zero)
throw new ArgumentOutOfRangeException("period");
if (action == null)
throw new ArgumentNullException("action");
var state1 = state;
var gate = new AsyncLock();
var cancel = s_cal.StartPeriodicTimer(() =>
{
gate.Wait(() =>
{
state1 = action(state1);
});
}, period);
return Disposable.Create(() =>
{
cancel.Dispose();
gate.Dispose();
action = Stubs<TState>.I;
});
}
我已经在IL DASM中检查了System. reactive . concurrency . defaultscheduler +<>c__DisplayClass9 ' 1[[System. net]。__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].b__6()为以下lambda编译:
() =>
{
gate.Wait(() =>
{
state1 = action(state1);
});
}
看起来lambda () => { state1 = action(state1); }
被传递为null。但是这怎么可能呢?
可以重现异常。你需要传递一个选择器函数,它是null。也许你忘了初始化Select块中的函数。或者当调度器想要运行该类的实例时,该类的实例已不存在。这就是为什么它是可能的:
Func<long, int> selector = null;
var x = Observable.Interval(TimeSpan.FromSeconds(1)).Select(selector);