【问题标题】:Why doesn't the c# compiler check "staticness" of the method at call sites with a dynamic argument?为什么 c# 编译器不使用动态参数在调用站点检查方法的“静态性”?
【发布时间】:2011-12-27 16:46:31
【问题描述】:

为什么 C# 编译器不告诉我这段代码无效?

class Program
{
    static void Main(string[] args)
    {
        dynamic d = 1;
        MyMethod(d);
    }

    public void MyMethod(int i) 
    {
        Console.WriteLine("int");
    }
}

MyMethod 的调用在运行时失败,因为我试图从静态方法调用非静态方法。这很合理,但是为什么编译器在编译时不认为这是一个错误呢?

以下不会编译

class Program
{
    static void Main(string[] args)
    {
        dynamic d = 1;
        MyMethod(d);
    }
}

因此,尽管动态分派,编译器确实会检查 MyMethod 是否存在。为什么不验证“静态”?

【问题讨论】:

  • 请注意,这在 C# 7.3 中已更改;在链接的线程中查看我的(编辑过的)答案。

标签: c# c#-4.0 dynamic static


【解决方案1】:

这里的重载分辨率是动态的。在这段代码中可见sn -p:

class Program {
    public static void Main() {
        dynamic d = 1.0;
        MyMethod(d);
    }

    public void MyMethod(int i) {
        Console.WriteLine("int");
    }

    public static void MyMethod(double d) {
        Console.WriteLine("double");
    }
}

工作正常。现在将 1 分配给 d 并注意运行时失败。编译器无法在编译时合理地模拟动态重载解析,所以它不会尝试。

【讨论】:

  • 但是如果不存在名为“MyMethod”的实例方法,它应该会产生编译错误????显然编译器足够聪明,可以查看是否根本不存在 MyMethod" ......所以你的答案还没有说服我......也许你可以详细说明一下?:-)
  • 我不明白为什么(运行时)重载解析在调用站点处于静态方法时会考虑实例方法。
  • 因为它试图生成良好的诊断。程序员是否忘记添加重载?还是他忘记了 static 关键字?
  • 哦。静态方法中的编译时重载决议也考虑了实例方法。从来不知道。好的,它解释了运行时重载行为。嗯,再想一想,这使得重载解析在实例方法和静态方法中的工作方式完全相同,这可能是一件好事。
  • @Hans:我总是忘记新方法上的 static 关键字,所以我不认为这是一个极端情况:-)。我确实理解编译器通常不可能决定在运行时调用什么方法。我一直在寻找编译器在可能的情况下不阻止运行时错误的原因,例如“因为这将需要 X 而这反过来又会暗示 Y 和 Z,从而导致矛盾/歧义”。感谢您的帮助。
【解决方案2】:

当编译器发现对dynamic 类型变量的操作时,它将使用CallSite 对象发出该信息。 (CallSite 对象是关于调用的存储信息。)

在您的第一个示例中,它可以编译,因为编译器可以发出信息(例如调用类型、您要调用的方法等)。在第二个代码中,您尝试调用不存在的方法,因此编译器无法为您生成 IL 代码。

【讨论】:

  • 感谢您的宝贵时间。我不是在问为什么第二个示例无法编译,我完全同意编译器可以为第一个示例发出 IL。我要问的是为什么它允许第一个例子?为什么它不能帮助我记住在 MyMethod 中添加 static 关键字?
猜你喜欢
  • 1970-01-01
  • 2012-10-02
  • 1970-01-01
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多