Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is testing generic collections for referential equality in C# a silly idea?

I'm implementing a special case of an immutable dictionary, which for convenience implements IEnumerable<KeyValuePair<Foo, Bar>>. Operations that would ordinarily modify the dictionary should instead return a new instance.

So far so good. But when I try to write a fluent-style unit test for the class, I find that neither of the two fluent assertion libraries I've tried (Should and Fluent Assertions) supports the NotBeSameAs() operation on objects that implement IEnumerable -- not unless you first cast them to Object.

When I first ran into this, with Should, I assumed that it was just a hole in the framework, but when I saw that Fluent Assertions had the same hole, it made my think that (since I'm a relative newcomer to C#) I might be missing something conceptual about C# collections -- the author of Should implied as much when I filed an issue.

Obviously there are other ways to test this -- cast to Object and use NotBeSameAs(), just use Object.ReferenceEquals, whatever -- but if there's a good reason not to, I'd like to know what that is.

like image 995
David Moles Avatar asked Mar 13 '13 14:03

David Moles


2 Answers

An IEnumerable<T> is not neccessarily a real object. IEnumerable<T> guarantees that you can enumerate through it's states. In simple cases you have a container class like a List<T> that is already materialized. Then you could compare both Lists' addresses. However, your IEnumerable<T> might also point to a sequence of commands, that will be executed once you enumerate. Basically a state machine:

public IEnumerable<int> GetInts()
{
    yield return 10;
    yield return 20;
    yield return 30;
}

If you save this in a variable, you don't have a comparable object (everything is an object, so you do... but it's not meaningful):

var x = GetInts();

Your comparison only works for materialized ( .ToList() or .ToArray() ) IEnumerables, because those state machines have been evaluated and their results been saved to a collection. So yes, the library actually makes sense, if you know you have materialized IEnumerables, you will need to make this knowledge public by casting them to Object and calling the desired function on this object "manually".

like image 125
nvoigt Avatar answered Sep 27 '22 21:09

nvoigt


In addition what Jon Skeet suggested take a look at this February 2013 MSDN article from Ted Neward:

.NET Collections, Part 2: Working with C5

Immutable (Guarded) Collections

With the rise of functional concepts and programming styles, a lot of emphasis has swung to immutable data and immutable objects, largely because immutable objects offer a lot of benefits vis-à-vis concurrency and parallel programming, but also because many developers find immutable objects easier to understand and reason about. Corollary to that concept, then, follows the concept of immutable collections—the idea that regardless of whether the objects inside the collection are immutable, the collection itself is fixed and unable to change (add or remove) the elements in the collection. (Note: You can see a preview of immutable collections released on NuGet in the MSDN Base Class Library (BCL) blog at bit.ly/12AXD78.)

It describes the use of an open source library of collection goodness called C5. Look at http://itu.dk/research/c5/

like image 39
pero Avatar answered Sep 27 '22 21:09

pero