none
IStructuralComparable.CompareTo - Returning Unexpected Results RRS feed

  • Question

  • IStructuralComparable.CompareTo is supposed to return -1, 0, or 1.  However, I am seeing it return -2, 0, or 2.  I am currently using the .NET 4.6 framework to build SSIS packages in VS2013 for SQL Server 2014.

    When I execute the following C# statements, I did not get the expected -1, 0, or 1.  Any reason why?

    // Returns -2
    ((IStructuralComparable) Convert.FromBase64String(startLSN)).CompareTo(Convert.FromBase64String(endLSN), Comparer<byte>.Default)

    // Returns 0
    ((IStructuralComparable) Convert.FromBase64String(startLSN)).CompareTo(Convert.FromBase64String(startLSN), Comparer<byte>.Default)

    // Returns 2
    ((IStructuralComparable) Convert.FromBase64String(endLSN)).CompareTo(Convert.FromBase64String(startLSN), Comparer<byte>.Default)

    Monday, October 16, 2017 4:20 PM

Answers

  • I believe the documentation is incorrect. CompareTo is always defined as returning < 0, 0 or > 0 so that implementation details can return back whatever value is best for them. The documentation for IStructuralComparable is the only place I've seen where it was explicit.

    While it is an interface so an implementation can do whatever it wants, the documentation states that it calls the IComparer passed in and returns it's results. IComparer uses the standard < 0, 0 and > 0 return values. The default comparer provided by the framework will return -1 or 1 when dealing with nulls but otherwise defer to the IComparable implementation of the underlying type.

    For strings using ordinal comparison, the return value can be many different values (depending upon where it detects the difference). At one point it simply substracts the length of the strings but at other times it will simply subtract the values of the first characters.

    var left = "aello";
    var right = "Gello";
    
    //-1
    var diff1 = String.Compare(left, right);
    
    //-6
    var diff2 = String.Compare(left, right, StringComparison.OrdinalIgnoreCase);
    
    //-1
    var diff3 = String.Compare(left, right, StringComparison.CurrentCultureIgnoreCase);

    The solution is to always use <0, 0, or >0 for comparisons. Then it will always be correct irrelevant of the implementation.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by J I M B O Monday, October 16, 2017 6:15 PM
    Monday, October 16, 2017 5:46 PM
    Moderator