A colleague has passed me an interesting code sample that crashes with an InvalidProgramException (“CLR detected an Invalid Program”) when run.
The problem seems to occur at JIT time, in that this compiles fine but throws the exception just before the method with the “offending” line is called – I guess as it is being JIT’d.
The line in question is calling Enumerable.ToDictionary and passing in a Func as the second argument.
If the Func argument is fully specified with a lambda it works; if it is specified as a method group, if fails. Surely these two are equivalent?
This has me stumped (and the colleague who discovered it!) – and it certainly seems like a JIT error.
[EDIT: Sorry – I got the pass and fail cases the wrong way round in the code sample – now corrected (description above was correct)]
Does anyone have an explanation?
using System;
using System.Linq;
internal class Program
{
private static void Main(string[] args)
{
Test.Try();
}
}
public class Test
{
public static readonly int[] integers = new[] { 1, 3, 5 };
public static void Try()
{
var line = new Line { A = 3, B = 5 };
// PASSES
var dict = integers.ToDictionary<int, int, decimal>(i => i, i => line.Compute(i));
// FAILS
//var dict = integers.ToDictionary<int, int, decimal>(i => i, line.Compute);
Console.WriteLine(string.Join(" ", dict.Select(kv => kv.Key + "-" + kv.Value)));
}
}
public class Line
{
public decimal A;
public decimal B;
}
public static class SimpleCompute
{
public static decimal Compute(this Line line, int value)
{
return line.A*value + line.B;
}
}
Compiler bug.
For info, I have the async CTP, which might be related;
cscreports: 4.0.30319.440Seems to be a difference between:
so let’s look in reflector:
vs
If you look in the broken version, it only loads one delegate. Compiler bug, basically:
all of the above is “check whether the cached
i => iexists; if not create it; then load it”. It never does anything with the second delegate. Consequently, there aren’t enough values on the stack to make the method call.