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

Jos*_*her 5 c# dynamic c#-4.0

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

dle*_*lev 5

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

其原因整个表达式是dynamic是,在不知道参数的编译时类型,过载分辨率不能不执行,所以返回类型的方法的不能也不会被知的.


Jon*_*eet 5

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

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

  • d is SomeType(总是被认为是bool)
  • 演员,直接和使用 as

就我记忆而言,虽然我可能会弄错......

现在语言本来可以设计成这样的情况下,这种情况会静静地将调用解析Build为唯一明智的 - 毕竟,不可能d任何类型可以改变调用哪种方法 - 而是指定确切的规则.会使语言规范(和编译器)显着地复杂化,获得相对较少的收益.