响应式扩展——AsyncLock.Wait抛出ArgumentNullException



当使用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);

相关内容

  • 没有找到相关文章