I was recently surprised by the way the compiler caches delegates when use use non-capturing delegates and lambdas. Take the following code (available at SharpLab):
using System;
public class C
{
static void Use(int x, int y)
{
// #1 - Allocates delegate per call
SomeMethod(Add);
// #2 - Caches delegate, doesn't allocate each time
SomeMethod((x, y) => Add(x, y));
// #3 - Allocates delegate per call
SomeMethod(LocalAdd);
// #4 - Caches delegate, doesn't allocate each time
SomeMethod((a, b) => LocalAdd(a, b));
static int LocalAdd(int a, int b)
{
return a + b;
}
}
static int Add(int x, int y)
{
return x + y;
}
static int SomeMethod(Func<int, int, int> func)
{
return func(1, 2);
}
}
I was surprised to see that in case #1 and #3 the compiler doesn't bother to cache the Func delegate it creates. I did wonder if the reason for #1 is down to historic reason (maybe this is how it was done before generics and lambdas), but the fact that passing the local function directly does the same suggests otherwise.
So, my question is, why doesn't the compiler cache the delegate it all cases? It seems odd that I have to use the more wordy lambda syntax in order to create a cached value. Why do I have to rewrite this:
SomeMethod(LocalAdd);
as
SomeMethod((a, b) => LocalAdd(a, b));
In order to get the compiler to cache the delegate and therefore generate less garbage?