Unknown breaking change in .NET 4?

Today I ran into a breaking change in .NET 4 which I couldn't find in the documentation. It's about binding a linq to objects query to a BindingSource's DataSource in winforms. The code works properly in .NET 3.5, but crashes in .NET 4:

_firstRelationshipsBindingSource.DataSource = 
                    from relationship in GuiStateSingleton.GetInstance().CurrentProject.
                            GetAllRelationshipsForEntity(selectedEntity, true)
                    where ((relationship.RelationshipType == EntityRelationshipType.ManyToOne) &&
                            (relationship.EndVertex==selectedEntity)) ||
                        ((relationship.RelationshipType == EntityRelationshipType.OneToMany) &&
                            (relationship.StartVertex == selectedEntity))
                    select relationship;

This binding source is bound to a simple winforms combo box. When the selection changes, I simply do:

_relationshipOneViewer.ToView = (RelationshipEdge)_relationshipOneComboBox.SelectedItem;

This works, because the relationship viewer can handle 'null' values when there's no selected item present. According to the query, the elements can be of type RelationshipEdge, the type of 'relationship' in the query.

In .NET 3.5, this works fine. If there are no elements returned by the query, this code will never hit, and even if it would, ToView would be set to null and everyone is happy. In .NET 4, it's a different story: SelectedItem is set to a value even if there are no elements in the linq to objects query, namely a WhereEnumerableIterator instance. It works OK if the query returns values, but when the query is empty, the WhereEnumerableIterator instance is ending up as the 'selected' item, causing the cast to go wrong.

It's easy to fix this of course: append a .ToList() to the query or use 'as' instead of the cast. The problem is that this issue is never going to pop up in previous .NET versions, so in general developers won't think about this.

I don't know whether this is a bug in .NET 4 or a breaking change. I can't think of a reason why one would change the .NET framework for this reason, so it looks like a bug. Either way, the only way to get rid of it is to work around it, as Microsoft isn't shipping fixes on a regular basis.

UPDATE: When I add a .ToList(), the code works as expected, so the issue isn't in BindingSource but in the enumerator.

4 Comments

  • What error are you getting? You say crash but what is the details on this?

  • The error is a cast exception, can't cast a WhereEnumerableIterator to RelationshipEdge on the line: _relationshipOneViewer.ToView = (RelationshipEdge)_relationshipOneComboBox.SelectedItem;

    I don't get that exception in .NET 3.5. Same application (.exe) -> first ran it on .NET 3.5: works. Then on .NET 4 -> fails with exception. Appending a .ToList() solves it

  • Hello Frans.

    Try change your code into:
    _relationshipOneViewer.ToView = _relationshipOneComboBox.SelectedItem as RelationshipEdge;

    This will return null in case of .SelectedItem isn't a RelationshipEdge instance - and no exception will occur :)

  • @Nikolaj: Yes I know (I mentioned it in the post ;)), and it fixes it, similar to a .ToList() call on the query, the point is: the enumerator shouldn't be in the list of items of the combo box, as that's a change of behavior which IMHO isn't justified (i.e. it's a bug in .net 4). So while it's fixable, the change breaks code without reason to as the type of the element in the list of items in the combo box is always RelationshipEdge, never some enumerator.

Comments have been disabled for this content.