这不是一个真正的答案,但我试图展示编译器的作用。所以尝试一个更简单的程序版本:
private static void Main(string[] args)
{
Method1();
Method2();
}
private static void Method1()
{
var expando = new ExpandoObject() as IDictionary<string, object>;
expando["key"] = 1;
}
private static void Method2()
{
dynamic expando = new ExpandoObject() as IDictionary<string, object>;
expando["key"] = 1;
}
使用ILSpy,您可以看到编译器创建的内容,甚至在使用任何运行时之前:
[CompilerGenerated]
private static class <Method2>o__SiteContainer0
{
public static CallSite<Func<CallSite, object, string, int, object>> <>p__Site1;
}
private static void Main(string[] args)
{
Program.Method1();
Program.Method2();
}
private static void Method1()
{
IDictionary<string, object> expando = new ExpandoObject();
expando["key"] = 1;
}
private static void Method2()
{
object expando = new ExpandoObject();
if (Program.<Method2>o__SiteContainer0.<>p__Site1 == null)
{
Program.<Method2>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, string, int, object>>.Create(Binder.SetIndex(CSharpBinderFlags.None, typeof(Program), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.Constant, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.Constant, null)
}));
}
Program.<Method2>o__SiteContainer0.<>p__Site1.Target(Program.<Method2>o__SiteContainer0.<>p__Site1, expando, "key", 1);
}
Method1 应该很清楚,因为编译器只是将 var 更改为 IDictionary 并按预期使用 expando。
在这里的 Method2 中,编译器执行了“魔术”。如this answerIDictionary 中所述,IDictionary 是一个显式接口,无法通过类实例访问。
如果将动态转换为 IDictionary,编译器会创建一个非常不同的代码:
private static void Method3()
{
dynamic expando = new ExpandoObject();
((IDictionary<string, object>)expando)["key"] = 1;
}
会变成
[CompilerGenerated]
private static class <Method3>o__SiteContainer0
{
public static CallSite<Func<CallSite, object, IDictionary<string, object>>> <>p__Site1;
}
private static void Method3()
{
object expando = new ExpandoObject();
if (Program.<Method3>o__SiteContainer0.<>p__Site1 == null)
{
Program.<Method3>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, IDictionary<string, object>>>.Create(Binder.Convert(CSharpBinderFlags.ConvertExplicit, typeof(IDictionary<string, object>), typeof(Program)));
}
Program.<Method3>o__SiteContainer0.<>p__Site1.Target(Program.<Method3>o__SiteContainer0.<>p__Site1, expando)["key"] = 1;
}
如您所见,CallSite 现在使用 IDictionary 类型。