3

I have spent two days chasing down an evil bug. I narrowed down the problem with this test case demonstrating different behavior for different collection classes that implement the same interface. Specifically Contains(null) throws a NullArgumentException for ImmutableSortedSet but not for Array or the mutable SortedSet.

using System.Collections.Generic;
using System.Collections.Immutable;
using Xunit;

public class SortedSetSpec
{
    [Fact]
    public void WTFNullCheck()
    {
        var data = new[] {"a", "b", "c", "d"};

        SortedSet<string> ss = new SortedSet<string>(data);
        ImmutableSortedSet<string> iss = ss.ToImmutableSortedSet();

        // This passes
        data.Contains(null).Should().BeFalse();

        // This passes
        ss.Contains(null).Should().BeFalse();

        // This throws an exception
        iss.Contains(null).Should().BeFalse();


    }
}

Given that all classes Array / SortedSet and ImmutableSortedSet implement ICollection<T> shouldn't they have the same behavior on the Contains(null) call?

The bug manifested itself when I data bound an ImmutableSortedSet to the ItemsSource property of a listbox.

 <ListBox x:Name="ListBox" Margin="2" 
          ItemsSource="{Binding WorkflowTags}" 
          SelectedItem="{Binding SelectedTag}" >
 </ListBox>

The problem is that at some point deep in the databinding code ListBox (aka Selector ) asks the collection Contains(null)?? and then it crashes if I've databound an ImmutableSortedSet.

So is this a bug with ImmutableCollections or with WPF or is it expected behavior and I should know better than to use ImmutableSortedSet?

The code within ImmutableSortedSet that is causing the problem can be found in the corefx github repo

/// <summary>
/// See the <see cref="IImmutableSet{T}"/> interface.
/// </summary>
public bool Contains(T value)
{
    Requires.NotNullAllowStructs(value, nameof(value));
    return _root.Contains(value, _comparer);
}
bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
  • I suspect that because you can't *add* a null to an `ImmutableSortedSet`, Microsoft have reasoned that you shouldn't be able to see if it contains a null. – Matthew Watson Jan 23 '17 at 16:03
  • I don't buy that. The ICollection interface where ``Contains`` is defined doesn't preclude asking if null is in there. I would accept that if you tried to add null to the collection it should throw but not asking if it contains null. – bradgonesurfing Jan 23 '17 at 16:05
  • I've added a bug report at https://github.com/dotnet/corefx/issues/15403 – bradgonesurfing Jan 23 '17 at 16:11
  • 1
    I'm just suggesting that's how Microsoft's thinking went; clearly it violates the Liskov substitution principle! – Matthew Watson Jan 23 '17 at 16:11
  • Sorry. I don't mean you are wrong. I mean the reasoning from the MS developer was wrong. – bradgonesurfing Jan 23 '17 at 16:12

0 Answers0