Exception with orderBy C#



  • I have an exception that seems impossible.

    Here's the exception stack.

    exception System.NullReferenceException: Object reference not set to an instance of an object.
       at MyClass.<>c.<get_MyThings>b__15_0(MyThing x)
       at System.Linq.EnumerableSorter`2.ComputeKeys(TElement[] elements, Int32 count)
       at System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count)
       at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__1.MoveNext()
       at MS.Internal.Data.EnumerableCollectionView.LoadSnapshotCore(IEnumerable source)
       at MS.Internal.Data.EnumerableCollectionView..ctor(IEnumerable source)
       at MS.Internal.Data.ViewManager.GetViewRecord(Object collection, CollectionViewSource cvs, Type collectionViewType, Boolean createView, Func`2 GetSourceItem)
       at MS.Internal.Data.DataBindEngine.GetViewRecord(Object collection, CollectionViewSource key, Type collectionViewType, Boolean createView, Func`2 GetSourceItem)
       at System.Windows.Data.CollectionViewSource.GetDefaultCollectionView(Object source, Boolean createView, Func`2 GetSourceItem)
       at System.Windows.Data.CollectionViewSource.GetDefaultCollectionView(Object source, DependencyObject d, Func`2 GetSourceItem)
       at System.Windows.Controls.ItemCollection.SetItemsSource(IEnumerable value, Func`2 GetSourceItem)
       at System.Windows.Controls.ItemsControl.OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
       at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
       at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
       at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
       at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
       at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
       at System.Windows.Data.BindingExpressionBase.Invalidate(Boolean isASubPropertyChange)
       at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
       at MS.Internal.Data.ClrBindingWorker.NewValueAvailable(Boolean dependencySourcesChanged, Boolean initialValue, Boolean isASubPropertyChange)
       at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)
       at MS.Internal.Data.PropertyPathWorker.RefreshValue()
       at MS.Internal.Data.ClrBindingWorker.ScheduleTransferOperation(Object arg)
       at MS.Internal.Data.DataBindEngine.ProcessCrossThreadRequests()
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
    
    

    Here's the accessor property.

            public IEnumerable<MyThing> MyThings => _myThingsDictionary.Values.OrderBy(x => x.SortOrder);
    

    Here's the only place that assigns to the dictionary.

    _myThingsDictionary[otherThing._ID] = new MyThing(someArguments);
    

    According to the exception, x is null, but how is that possible?



  • Maybe a null/nullable item in your dictionary, or an item where SortOrder is null? Or your property is being called when you aren't expecting it, perhaps from some kind of UI event that's firing during view initialization but before the dictionary is usable.

    That stack trace is surprisingly ugly for .NET.



  • @mott555 said in Exception with orderBy C#:

    Maybe a null/nullable item in your dictionary, or an item where SortOrder is null? Or your property is being called when you aren't expecting it, perhaps from some kind of UI event that's firing during view initialization but before the dictionary is usable.

    That stack trace is surprisingly ugly for .NET.

    SortOrder is int. I don't think those can be null, right?

    It's being called during WPF's initialize for a view. You can tell by the last two lines, "ExceptionWrapper.InternalRealCall and TryCatchWhen"


  • And then the murders began.

    @xaade said in Exception with orderBy C#:

    SortOrder is int. I don't think those can be null, right?

    int can't be null (should be initialized to 0), int? can be.



  • @xaade said in Exception with orderBy C#:

    It's being called during WPF's initialize for a view.

    That could be a problem. I've run into issues where UI events fire really early and try to databind to things that don't exist yet, for example if the backing item is created/loaded/initialized during a Loaded event handler which actually happens after certain UI events.

    To avoid that, I usually set all my databinding up in XAML but don't assign a DataContext until the page/view's Loaded event fires (assign DataContext in the Loaded handler). Loaded always seems to run after the UI is finished building. There might be a better or more official way.



  • @unperverted-vixen said in Exception with orderBy C#:

    @xaade said in Exception with orderBy C#:

    SortOrder is int. I don't think those can be null, right?

    int can't be null (should be initialized to 0), int? can be.

    @mott555

    Thanks!!!

    You guys unwittingly gave me something to go on.

    SortOrder is a property. I'm such a dumbass. I saw the int, and stopped investigating.

            public int SortOrder
            {
                get => InsideThing.SortOrder;
                set => Set(ref InsideThing.SortOrder, value);
            }
    

    Oh you sneak asshole.



  • So you're sure that the dictionary exists at this point? Because it's definitely either that or one of the dictionary values. Have you tried putting a breakpoint in the lambda? (Many people don't realize that with your cursor in one, F9 will put one inside it, even though it isn't a 'line'.



  • Crud.... no dice.

    MyThing.InsideThing is set on creation of MyThing, never set to null, and never updated, only referenced.



  • Which thread is the stack from? The main thread?
    Or perhaps another thread that could be accessing the dictionary as you're filling it?



  • Can you reproduce it locally? Set Visual Studio to break when NullReferenceException is thrown?


  • Impossible Mission - B

    @ben_lubar said in Exception with orderBy C#:

    Can you reproduce it locally? Set Visual Studio to break when NullReferenceException is thrown?

    Yeah, this was my first reaction to seeing this post: "what does the debugger show when you hit this exception?"



  • @ben_lubar said in Exception with orderBy C#:

    Can you reproduce it locally? Set Visual Studio to break when NullReferenceException is thrown?

    Wish I could.

    QA swears he can, but he's on vacation until Monday.



  • It was a freakin race condition.

    Ok, so, for a short period of time, a MyThing is created, but InsideThing was not set.

    During that vanishingly small amount of time, WPF, in its glorious wisdom, decides to access the MyThings property.

    It tries to sort, but can't access SortOrder because InsideThing was null.

    Marvelous.



  • Does the problem go away if you add a .ToList() after the .OrderBy() ? A Dictionary is not threadsafe, so if a thread is assigning the otherThing while the view is updating you could well get into this behaviour, I think.





  • @xaade Okay, yeah, WPF immediately reads all properties that are bound, before initializing even I think. The constructor is the only code guaranteed to run first.


  • Considered Harmful

    @magus said in Exception with orderBy C#:

    WPF immediately reads all properties that are bound, before initializing even I think

    Constructor injection, kicking and screaming.



  • @gribnit It's the only way to be sure.


  • And then the murders began.

    @magus said in Exception with orderBy C#:

    Okay, yeah, WPF immediately reads all properties that are bound, before initializing even I think. The constructor is the only code guaranteed to run first.

    @xaade said in Exception with orderBy C#:

    MyThing.InsideThing is set on creation of MyThing, never set to null, and never updated, only referenced.

    Well, either it's set in the constructor, so @magus is wrong, or it's not set in the constructor, so it's not actually set on creation like @xaade said. Which is it? 🚎



  • @unperverted-vixen He never said it was in the constructor, to be fair.



  • @magus said in Exception with orderBy C#:

    @xaade Okay, yeah, WPF immediately reads all properties that are bound, before initializing even I think. The constructor is the only code guaranteed to run first.

    A series of MyThings are being added to the dictionary, and NotifyPropertyChanged is being called after each.

    Whenever WPF decides to actually update based on the Notify, there's a small window where MyThing is created before it is assigned an InsideThing, where InsideThing will be null if WPF accesses MyThings property.

    This is why it is hard to duplicate.

    I changed MyThing so that the constructor requires InnerThing. This should close that gap.


Log in to reply