存储“IntConverter”实例的位置在哪里?

时间:2015-07-07 13:57:29

标签: c# .net expression-trees

我们假设我们有以下计划:

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);
    }
}

我理解大部分代码,但令我生气的部分是RegisterImplementation方法。在字典中,我们存储了一个Func<object, object>实例,converter没有存储在任何地方,所以我假设当我们离开该方法时我们失去了本地引用。

那么我们怎样才能在字典中调用该函数并使用IntConverter的引用?它存放在哪里?在Func<object, object>内?

2 个答案:

答案 0 :(得分:2)

首先,值得清楚的是,您的问题实际上并不涉及表达式树 - 您的lambda表达式只是被转换为委托。

现在,lambda表达式是这样的:

(obj) => converter.Convert(obj)

捕获局部变量converter。实际上,这意味着C#编译器将创建一个新类,如下所示:

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

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

然后您的方法将转换为:

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);
}

因此委托的目标将是新类的实例,而 使转换器保持活动状态。

答案 1 :(得分:1)

lambda代码(obj) => converter.Convert(obj)使用本地converter。这个lambda代码保持了本地的存在。