使用动态变量作为方法参数会禁用(某些)编译器检查

时间:2016-04-13 08:56:46

标签: c# dynamic compiler-errors

有人可以向我解释为什么如果将动态变量用作方法调用的参数,编译器不会检查函数的返回类型吗?

class Program
{
    static void Main(string[] args)
    {
        // int a = GetAString(1); // Compiler error CS0029 Cannot impilicitly convert type 'string' to 'int'

        dynamic x = 1;

        int b = GetAString(x); // No compiler error -> Runtime Binder Exception 

        // int c = (string)GetAString(x); // Compiler error CS0029 Cannot impilicitly convert type 'string' to 'int'
    }

    static string GetAString(int uselessInt)
    {
        return "abc";
    }
}

2 个答案:

答案 0 :(得分:2)

通过使用dynamic,编译器将在您使用动态参数的任何位置生成调用站点。此调用站点将尝试在运行时解析该方法,如果找不到匹配方法,则会引发异常。

在您的示例中,呼叫网站会检查x,并发现它是int。然后,它会查找名为GetAString的任何方法,它们会使用int并找到您的方法并生成代码以进行调用。

接下来,它将生成代码以尝试将返回值分配给b。所有这些仍然在运行时完成,因为使用动态变量使整个表达式需要运行时评估。调用网站会查看是否可以生成代码以将string分配给int,因为它不会引发异常。

顺便说一下,您的示例没有多大意义,因为您似乎想要string分配给int您的GetAsString方法甚至返回非数值,所以它永远不会分配给int。如果你写:

dynamic x = 1;
string b = GetAsString(x);

然后一切都应该有效。

答案 1 :(得分:1)

在一般情况下,候选人不一定像你的一样直截了当。例如,请考虑以下两种方法:

string M(string a) => a;
char[] M(char[] a) => a;     

这段代码应该建议什么作为最后一个变量的类型?

dynamic d = SomeExpression();
var s = M(d);

此时,C#的设计者必须做出选择:

  1. 断言使用dynamic参数调用的方法的返回值本身也是dynamic
  2. 选择可以从该组的所有方法分配的类型(例如IEnumerable<char>)。
  3. 后一种选择基本上就是您在问题中描述的内容。 C#设计师采用了前一种选择。设计决策的可能原因可能是:

    • 也许他们认为如果您在表达式中选择dynamic,那么您更有可能希望继续在任何相关表达式上使用dynamic ,直到你再次明确选择退出。
    • 也许他们没有引入dynamic来启用多次发送,所以他们并不想通过包含静态类型的规定来进一步鼓励它。
    • 也许他们认为包含这些规定会使规范膨胀或使语言难以理解。
    • 也许前一个选项更容易实现(假设您已经实现了dynamic的其余部分)并且他们认为另一个选项不值得花费更多的时间或精力。
    • 也许它在C#中实现起来并不那么简单。值类型可能需要装箱以匹配常见的超类型,这使事情变得复杂。原始指针类型完全不在统一的层次结构中。