I just finished debugging a problem, where our program crashed on a production server, but never on development machines.
I have made this small program, which I could reproduce the issue with:
using System;
using System.Collections.Generic;
using System.Linq;
namespace RunTimeBug
{
class Program
{
static void Main(string[] args)
{
var coll = new Collection {{"Test", new Data()}, {"Test2", new Data()}};
var dataSequence = coll.Cast<Data>().ToList();
Console.WriteLine(dataSequence.Count);
}
}
class Collection : Dictionary<string,Data>, IEnumerable<Data>
{
public new IEnumerator<Data> GetEnumerator()
{
foreach(var v in Values)
yield return v;
}
}
class Data { }
}
When running on my machine, this code prints "2". When running on the production server, it fails with the following exception:
Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.KeyValuePair
`2[System.String,RunTimeBug.Data]' to type 'RunTimeBug.Data'.
at System.Linq.Enumerable.<CastIterator>d__b0`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at RunTimeBug.Program.Main(String[] args)
The only difference I can find on these machines, is that the CLR Runtime is version 2.0.50727.4927 on machines, where it works, and version 2.0.50727.1433 on machines where it does not work.
As far as I can tell, the Cast extension method gets the wrong version of IEnumerable on the older machines, but the "right" one on newer machines.
Can anyone explain why I am seeing this ? What has changed between the 2 CLR Runtime versions, that might be causing this ?
Please note, I have already deployed a fix, and I am aware that the Collection class in the code above is poor design because it implements 2 different IEnumerable's. This was found "in the wild" in our product, so I would really like to know the exact cause.