views:

67

answers:

2

I'm running into an issue using a DataGridView bound to a iBindingListView implementation (third party dll) attached to a large collection.

There's a certain property in my collection type, named MyDateTime, which is a value class similar to DateTime, but also with some legacy code.

This struct implements iComparable, iComparable<T>, and iEquatable<T>.

The issue I'm having is this:

When I apply a sort to the iBindingListView on the MyDateTimeColumn, it ALWAYS uses the non-generic iComparer, causing hundreds of thousands of unnecessary boxing and unboxing.

When I use the Automatic Sorting provided by the DGV, it does a string sort on the column. Keeping this column "automatic" instead of programmatic for just this column would not be acceptable.

When I remove the non-generic iComparer, the generic one is still not used, it just does a string compare on the .ToString().

Am I missing something? Why is my generic comparer not bieng called on a sort?

+1  A: 

Unfortunately there's no way around this; at some point, the DataGridView is going to deal with the value as an object, meaning that it will have to be boxed if it's a value type.

Adam Robinson
Actually, not quite true `DataGridView` generally asks the view to *sort itself* via `IBindingListView.ApplySort` - the problem is that it is very hard to write an `ApplySort` implementation that doesn't box. It can be done, but it would be horrible.
Marc Gravell
I guess I don't understand why sorting on a DateTime member, which has the same interfaces implemented, can be done WITHOUT boxing, but when I use the myDateTime member, it does.
greggorob64
@greggorob64 - they can special-case an expected type like `DateTime`; not likely with your custom type. I'm actually surprised it avoids boxing even then.
Marc Gravell
@Marc: So am I; I would have expected it to box. And yes, you could ask the list to sort itself, but that would essentially require the list type to be aware of the members of its elements, or you could possibly expand the `PropertyDescriptor` object to allow it to compare the value of one element to the value of another (never actually dealing with the value itself). @greggorob64: How are you determining that the `DataGridView` *isn't* boxing `DateTime`.
Adam Robinson
Strictly by timing. In my list of 200k items, it takes about 3-4 seconds to sort a String property (which doesn't), 3-4 seconds to sort a datetime property, and 20 seconds to sort a myDateTime property (which boxes).The only conclusion I drew was that it either boxes unrealistically fast, or its not boxing at all.
greggorob64
@greggorob64: The only real way to know for sure is to take a look at how your source implements `ApplySort`.
Adam Robinson
+1  A: 

Ultimately this type of data-binding is often reflection-based, and reflection is object-based; so boxing is a reality. Actually, you can control this when implementing IBindingListView, but it would be a large amount of work, and I'm guessing they simply haven't (sensibly).

The simpler way to do this (which I'm assuming they are using) is to trust the PropertyDescriptor, calling GetValue and then using Comparer.Default.Compare(x,y). Once you've called GetValue there isn't any point not using the object you've already boxed (and would have to then unbox).

And if you don't trust the PropertyDescriptor you are getting into very implementation-specific code, that doesn't support the general ComponentModel view of the world (so it won't work on data-tables or bespoke models, etc).

Marc Gravell
I'm a little unsure of where you mention calleding "getvalue" at in the schema I have setup, could you elaborate? Thanks.
greggorob64
@greggorob64 - `DataGridView` and `IBindingListView` are based around an abstracted object-model (via `PropertyDescriptor`). This, for example, is how data-tables present their data as "columns", when a data-table *clearly* doesn't have properties matching your logical column-names. `PropertyDescriptor` has a `GetValue(obj)` method, which is what I am referring to. Likewise, automatic sorting involves it telling which property/properties should be involved by giving it the `PropertyDescriptor` instances.
Marc Gravell
@greggorob64 - this also allows you to add your own custom models via `ICustomTypeDescriptor` or `TypeDescriptionProvider`. You can get the *runtime* view of the props with `TypeDescriptor.GetProperties(someObject)` (or there is an overload for passing a `Type` instead of an instance). Note that there are lots of other interfaces involved in this; a complex and little-understood corner of the framework.
Marc Gravell
So in the end, implementing propertydescriptor is still going to end up boxing my struct though, so I won't see any performance increase I take it?
greggorob64
@greggorob: Yes, the `PropertyDescriptor` object, while able to deal with an entity in a strongly-typed, non-reflective way, must still accept and return the values as `object`, so your value will still be boxed.
Adam Robinson