Where is the instance of "IntConverter" stored?

Let's suppose we have the following program:

public class Program
{
    private static Dictionary<Type, Func<object, object>> converters = new Dictionary<Type, Func<object[], object>>();

    public static void Main(string[] args)
    {
         RegisterImplementation(new IntConverter());
         int value = (int) dic[typeof(int)]("4");
         Console.WriteLine(value); //Prints 4
    }

    private static RegisterImplementation<X>(IConverter<X> converter)
    {
         Type type = typeof(X);
         Func<object, object> conversion = (obj) => converter.Convert(obj);
         if(dic.ContainsKey(type))
             dic[type] = conversion;
         else
             dic.Add(type, conversion);
    }
}

public interface IConverter<X>
{
    X Convert(object obj);
}

public class IntConverter : IConverter<int>
{
    public int Convert(object obj)
    {
        return Convert.ToInt32(obj);
    }
}

I understand most of the code, but the part that's driving me mad is the RegisterImplementation method. In the dictionary we are storing a Func<object, object> instance, and the converter is not stored anywhere, so I am assuming we lose the local reference when we get out of the method.

So how can we call the function in the dictionary afterwards and use this reference of IntConverter? Where is it stored? Inside the Func<object, object>?

Jon Skeet
people
quotationmark

Firstly, it's worth being clear that your question doesn't actually involve expression trees at all - your lambda expression is just being converted into a delegate.

Now, that lambda expression is this:

(obj) => converter.Convert(obj)

That captures the local variable, converter. In practice, that means the C# compiler will have created a new class, like this:

private class UnspeakableName<X>
{
    public IConverter<X> converter;

    public object Method(object obj)
    {
        return converter(obj);
    }
}

Then your method will be converted into:

private static RegisterImplementation<X>(IConverter<X> converter)
{
     UnspeakableName<X> tmp = new UnspeakableName<X>();
     tmp.converter = converter;

     Type type = typeof(X);
     Func<object, object> conversion = tmp.Method;
     if(dic.ContainsKey(type))
         dic[type] = conversion;
     else
         dic.Add(type, conversion);
}

So the target of the delegate will be the instance of the new class, and that keeps the converter alive.

people

See more on this question at Stackoverflow