为什么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++; } }