为什么C#编译器不是静态方法调用实例方法的错误代码?

下面的代码有一个静态方法Foo() ,调用一个实例方法Bar()

 public sealed class Example { int count; public static void Foo( dynamic x ) { Bar(x); } void Bar( dynamic x ) { count++; } } 

它编译没有错误*,但在运行时生成运行时绑定exception。 正如所料,删除这些方法的dynamic参数会导致编译器错误。

那么为什么有一个dynamic参数允许编译代码? ReSharper也不会将其显示为错误。

在Visual Studio 2008中编辑1: *

编辑2:添加sealed因为子类可能包含静态Bar(...)方法。 即使是密封的版本,也可以在运行时调用实例方法以外的方法。

出于某种原因, 检查静态与非静态之前 ,重载parsing总是find最佳匹配。 请尝试使用所有静态types的代码:

 class SillyStuff { static void SameName(object o) { } void SameName(string s) { } public static void Test() { SameName("Hi mom"); } } 

这不会编译,因为最好的重载是一个string 。 但是,嘿,这是一个实例方法,所以编译器抱怨(而不是采取第二重载)。

另外:所以我认为原始问题的dynamic例子的解释是,为了一致,当types是dynamic的时候,我们也首先find最好的重载(只检查参数号和参数types等,而不是静态的非静态的),只有然后检查静态。 但这意味着静态检查必须等到运行时。 因此观察到的行为。

后期补充:一些背景为什么他们select做这个有趣的命令可以从这个博客文章由埃里克·利珀特推断。

Foo有一个dynamic的参数“x”,这意味着Bar(x)是一个dynamicexpression式。

示例具有如下方法是完全可能的:

 static Bar(SomeType obj) 

在这种情况下,正确的方法将被解决,所以语句Bar(x)是完全有效的。 有一个实例方法Bar(x)的事实是无关紧要的,甚至没有考虑到: 根据定义 ,因为Bar(x)是一个dynamicexpression式,所以我们已经推迟了运行时的parsing。

“dynamic”expression式在运行时会被绑定,所以如果你使用正确的签名或实例方法定义一个静态方法,编译器将不会检查它。

“正确”的方法将在运行时确定。 编译器无法知道在运行时是否有有效的方法。

“dynamic”关键字是为dynamic语言和脚本语言定义的,即使在运行时也可以随时定义该方法。 疯狂的事情

这里是一个样例,它处理整数,但没有string,因为方法是在实例上。

 class Program { static void Main(string[] args) { Example.Foo(1234); Example.Foo("1234"); } } public class Example { int count; public static void Foo(dynamic x) { Bar(x); } public static void Bar(int a) { Console.WriteLine(a); } void Bar(dynamic x) { count++; } } 

您可以添加一个方法来处理所有“错误”的调用,这是无法处理的

 public class Example { int count; public static void Foo(dynamic x) { Bar(x); } public static void Bar<T>(T a) { Console.WriteLine("Error handling:" + a); } public static void Bar(int a) { Console.WriteLine(a); } void Bar(dynamic x) { count++; } }