Menu

Sorting on Nullable<T> properties

Help
2006-08-18
2013-04-18
  • Tom Lokhorst

    Tom Lokhorst - 2006-08-18

    As a test I changed in /src/DemoCS/Item.cs the public DateTime PubDate to:

    public DateTime? PubDate
    {
        get
        {
            if (_pubDate.DayOfYear == DateTime.Now.DayOfYear)
                return null;
            else
                return _pubDate;
        }
        set { _pubDate = value.Value; }
    }

    Now it seems the sorting on the PubDate property doesn't work any more.

     
    • Andrew Davey

      Andrew Davey - 2006-08-25

      Have you run with the latest version of the library. I did make some changes to the comparison logic to re-support nulls (we lost it when I moved to dynamic code generation approach).

       
    • Tom Lokhorst

      Tom Lokhorst - 2006-08-26

      I'm using the 1.1.3.1 ZIPed release.

      But just to be clear, I'm not having problems with a null value, but with an instance of a Nullable<T>.

      For example, sorting on this property works:
      public DateTime PubDate { get; set; }

      But sorting on this property does not:
      public DateTime? PubDate { get; set; }

      ----------------------------

      I've now looked at the code and I think I've found the problem.

      The AggregateBindingListView.BuildComparison(string propertyName, ListSortDirection direction) method checks to see if pi.PropertyType is a IComparable [#1322].
      However, Nullable<T> does not implement IComparable, so the code falls back to o1.Equals(o2) [#1363].
      What it should do is:
      Nullable.Compare<T>(o1, o2);

      ----------------------------

      As a test, I've added the following code at line #1363:

                      else if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
                      {
                          return delegate(T o1, T o2)
                              {
                                  IComparable value1 = (IComparable) o1.GetType().GetProperty(pi.Name).GetValue(o1, null);
                                  object value2 = o2.GetType().GetProperty(pi.Name).GetValue(o2, null);

                                  int result = value1.CompareTo(value2);

                                  if (direction == ListSortDirection.Descending)
                                  {
                                      result *= -1;
                                  }

                                  return result;
                              };
                      }

      I don't know if this is fast or will even work correctly in al cases, but it seems to fix my particular problem. (I can now sort on a DateTime? property).
      However, this doesn’t use the Nullable.Compare<T>() method, so I think this might not be the best solution.

       
      • Andrew Davey

        Andrew Davey - 2006-08-27

        Thanks for your feedback Tom. I like to see people actually taking the time to hunt down a problem and not just tell me "it's broken"!

        I've been looking through how the .NET framework deals with Nullable<T> and it does seem to special case it. So your approach with the "if else" is along the right lines. We basically have the issue of want to call a generic function without actually having the generic parameters at compile time. The ideal solution would be to directly using Nullable.Compare<T>. However, I need to find out about referencing this generic static method...

         
    • Tom Lokhorst

      Tom Lokhorst - 2006-08-27

      Hunting down this problem improves my understanding of .NET, so I like trying to figure this out :-)

      I've found how to get the MethodInfo for a generic method:

      MethodInfo compareMethod = typeof(Nullable<>).GetMethod("Compare");
      MethodInfo genericCompareMethod = compareMethod.MakeGenericMethod(typeof(DateTime));

      And instead of typeof(DateTime) the runtime Type would be:

      Type valueType = pi.PropertyType.GetGenericArguments()[0];

      However I can’t seem to get to the Nullable<T> value of the property. When invoking the property’s GetValue method, the .NET runtime returns the actual ValueType inside the Nullable<T>. Since that is the case, this also works:

      [#1363]
      else if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
      {
          return BuildValueTypeComparison(pi, direction);
      }

      I’m not sure, but I think this might even be the best solution in this case.

       

Log in to post a comment.

MongoDB Logo MongoDB