I have the following code that exhibits a strange problem:
var all = new FeatureService().FindAll();
System.Diagnostics.Debug.Assert(all != null, \"FindAll must
After looking over the code over TeamViewer, and finally downloading, compiling and running the code on my own machine, I believe this is a case of compiler error in C# 4.0.
I've posted a question with request for verification, after managing to reduce the problem to a few simple projects and files. It is available here: Possible C# 4.0 compiler error, can others verify?
The likely culprit is not this method:
protected override List GetModels() {
var fs = new FeatureService();
var all = fs.FindAll();
var wr = new WeakReference(all);
System.Diagnostics.Debug.Assert(all != null, "FindAll must not return null");
System.Diagnostics.Debug.WriteLine(wr.IsAlive);
System.Diagnostics.Debug.WriteLine(all.ToString()); // throws NullReferenceException
return all;
}
But the method it calls, FeatureService.FindAll:
public List FindAll() {
string key = Cache.GetQueryKey("FindAll");
var value = Cache.Load>(key);
if (value == null) {
var query = Context.Features;
value = query.ToList().Select(x => Map(x)).ToList();
var policy = Cache.GetDefaultCacheItemPolicy(value.Select(x => Cache.GetObjectKey(x.Id.ToString())), true);
Cache.Store(key, value, policy);
}
value = new List();
return value;
}
If I changed the call in GetModels from this:
var all = fs.FindAll();
to this:
var all = fs.FindAll().ToList(); // remember, it already returned a list
then the program crashes with a ExecutionEngineException
.
After doing a clean, a build, and then looking at the compiled code through Reflector, here's how the output looks (scroll to the bottom of the code for the important part):
public List FindAll()
{
List value;
Func CS$<>9__CachedAnonymousMethodDelegate6 = null;
List CS$<>9__CachedAnonymousMethodDelegate7 = null;
string key = base.Cache.GetQueryKey("FindAll");
if (base.Cache.Load>(key) == null)
{
if (CS$<>9__CachedAnonymousMethodDelegate6 == null)
{
CS$<>9__CachedAnonymousMethodDelegate6 = (Func) delegate (Feature x) {
return this.Map(x);
};
}
value = base.Context.Features.ToList().Select(((Func) CS$<>9__CachedAnonymousMethodDelegate6)).ToList();
if (CS$<>9__CachedAnonymousMethodDelegate7 == null)
{
CS$<>9__CachedAnonymousMethodDelegate7 = (List) delegate (FeatureModel x) {
return base.Cache.GetObjectKey(x.Id.ToString());
};
}
Func policy = (Func) base.Cache.GetDefaultCacheItemPolicy(value.Select((Func) CS$<>9__CachedAnonymousMethodDelegate7), true);
base.Cache.Store>(key, value, (CacheItemPolicy) policy);
}
value = new List();
bool CS$1$0000 = (bool) value;
return (List) CS$1$0000;
}
Notice the 3 last lines of the method, here's what they look like in the code:
value = new List();
return value;
here's what Reflector says:
value = new List();
bool CS$1$0000 = (bool) value;
return (List) CS$1$0000;
It creates the list, then casts it to a boolean, then casts it back to a list and returns it. Most likely this causes a stack problem.
Here's the same method, in IL (still through Reflector), I've stripped away most of the code:
.method public hidebysig instance class [mscorlib]System.Collections.Generic.List`1 FindAll() cil managed
{
.maxstack 5
.locals init (
[0] string key,
[1] class [mscorlib]System.Collections.Generic.List`1 'value',
[2] class [System.Data.Entity]System.Data.Objects.ObjectSet`1 query,
[3] class [mscorlib]System.Func`2 policy,
[4] class [mscorlib]System.Func`2 CS$<>9__CachedAnonymousMethodDelegate6,
[5] class [mscorlib]System.Collections.Generic.List`1 CS$<>9__CachedAnonymousMethodDelegate7,
[6] bool CS$1$0000,
[7] char CS$4$0001)
...
L_009f: newobj instance void [mscorlib]System.Collections.Generic.List`1::.ctor()
L_00a4: stloc.1
L_00a5: ldloc.1
L_00a6: stloc.s CS$1$0000
L_00a8: br.s L_00aa
L_00aa: ldloc.s CS$1$0000
L_00ac: ret
}
Here's a screencast showing the debug session, if you just want the Reflector output, skip to about 2:50.