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).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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:
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.
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).
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.
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...
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.