ExpandoObject动态添加项目时的古怪行为

时间:2015-07-08 21:15:41

标签: c# dynamic-programming

所以我使用ExpandoObject添加动态填充到字符串中的属性。我将在稍后使用它们绑定到DataGrid。下面给出了代码的两个变体,看起来它们正在做同样的事情(对我来说至少)但是一个失败而一个没有。有人可以帮我理解为什么会这样吗?

代码失败

    dynamic dynamo = new ExpandoObject() as IDictionary<string,object>;
    string words[] = basestring.Split('|');
    foreach(string word in words)
   {
        dynamo[word] = word.ToUpperInvariant();
   }

成功代码

 dynamic dynamo = new ExpandoObject();
 var dynamoose = dynamo as as IDictionary<string,object>; //Notice the cast
 string words[] = basestring.Split('|');
 foreach(string word in words)
{
   dynamoose[word] = word.ToUpperInvariant();
}

`

2 个答案:

答案 0 :(得分:0)

您的代码不会直接运行。我无法获得双重投射工作。你的字符串单词[]没有编译,所以我把它改成字符串[]字。

从那里开始,失败的代码给了我这个有价值的信息:

  

其他信息:无法将带有[]的索引应用于表达式   类型&#39; System.Dynamic.ExpandoObject&#39;

你的第二段代码有效,因为你有一个IDictionary实例,而失败的一块试图在动态上调用[] -indexing运算符。

答案 1 :(得分:0)

这不是一个真正的答案,但我试图展示编译器的功能。所以试试一个更简单的程序版本:

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中,编译器执行&#34; magic&#34;。如this answer中所述,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类型。