方法中动态方法返回值的显式转换不允许调用扩展方法

时间:2011-10-26 11:42:38

标签: c# c#-4.0 dynamic

以下代码演示了我的问题:

public class DynamicExample
{
    public void DoSomething()
    {
        var x = new ExpandoObject();
        dynamic d = x;
        d.GetString = (Func<string>)(() => "Some Value");

        d.GetString().SomeStringExtension(); // Doesn't work - expected
        ((string)d.GetString()).SomeStringExtension(); // Works - expected
        Build(d).SomeStringExtension(); // Doesn't work - unexpected?
    }

    private static string Build(dynamic d)
    {
        return (string)d.GetString();
    }
}

public static class StringExtensions
{
    public static int SomeStringExtension(this string s)
    {
        return s.Length;
    }
}

问题是,为什么编译器在将内联类型转换为扩展方法调用并将其转换为单独的方法之间存在差异?

2 个答案:

答案 0 :(得分:5)

如果将鼠标悬停在VS2010中的Build(d)上,您会看到整个表达式被视为动态表达式,并在运行时解析。因此,它无法绑定到扩展方法(否则会在编译时发生。)

整个表达式为dynamic的原因是在不知道参数的编译时类型的情况下,不执行重载决策不能,因此返回 - 不能的方法的类型也是未知的。

答案 1 :(得分:5)

Build(d)仍然是一个动态表达式 - 该方法的编译时类型为dynamic,即使可以确切地看到正在发生的事情。这意味着扩展方法不起作用。

基本上,编译器遵循相当简单的规则来确定表达式的类型,并且几乎涉及dynamic的任何表达式最终被视为动态表达式。例外情况是:

  • d is SomeType(始终被视为bool
  • 直播和使用as
  • 进行投射

就我所记得的而言,尽管我可能会弄错......但

现在语言可以的设计使得这种情况静态解析对Build的调用是唯一明智的 - 毕竟,这是不可能的for d任何类型,它会改变调用哪个方法 - 但指定确切的规则会使语言规范(和编译器)相对较少变得复杂增益。