[英]Why does the C# compiler not fault code where a static method calls an instance method?
The following code has a static method, Foo()
, calling an instance method, Bar()
:以下代码有一个静态方法Foo()
,调用实例方法Bar()
:
public sealed class Example
{
int count;
public static void Foo( dynamic x )
{
Bar(x);
}
void Bar( dynamic x )
{
count++;
}
}
It compiles without error* but generates a runtime binder exception at runtime.它编译时没有错误*,但在运行时生成运行时绑定器异常。 Removing the dynamic parameter to these methods causes a compiler error, as expected.正如预期的那样,删除这些方法的动态参数会导致编译器错误。
So why does having a dynamic parameter allow the code to be compiled?那么为什么有一个动态参数允许编译代码呢? ReSharper doesn't show it as an error either. ReSharper 也不会将其显示为错误。
Edit 1: *in Visual Studio 2008编辑 1: *在 Visual Studio 2008 中
Edit 2: added sealed
since it's possible that a subclass could contain a static Bar(...)
method.编辑 2:添加sealed
因为子类可能包含静态Bar(...)
方法。 Even the sealed version compiles when it's not possible that any method other than the instance method could be called at runtime.当不可能在运行时调用除实例方法之外的任何方法时,即使是密封版本也会编译。
UPDATE: Below answer was written in 2012, before the introduction of C# 7.3 (May 2018) .更新:以下答案写于 2012 年,在 C# 7.3 (May 2018) 推出之前。 In What's new in C# 7.3 , the section Improved overload candidates , item 1, it is explained how the overload resolution rules have changed so that non-static overloads are discarded early.在C# 7.3 的新增功能中,改进的重载候选部分的第 1 项中,解释了重载解析规则如何更改以便提前丢弃非静态重载。 So the below answer (and this entire question) has mostly only historical interest by now!所以下面的答案(以及整个问题)现在大多只有历史意义!
(Pre C# 7.3:) (C# 7.3 之前:)
For some reason, overload resolution always finds the best match before checking for static versus non-static.出于某种原因,重载解析总是在检查静态与非静态之前找到最佳匹配。 Please try this code with all static types:请尝试所有静态类型的代码:
class SillyStuff
{
static void SameName(object o) { }
void SameName(string s) { }
public static void Test()
{
SameName("Hi mom");
}
}
This will not compile because the best overload is the one taking a string
.这将无法编译,因为最好的重载是采用string
重载。 But hey, that's an instance method, so compiler complains (instead of taking the second-best overload).但是,嘿,这是一个实例方法,所以编译器会抱怨(而不是采用第二好的重载)。
Addition: So I think the explanation of the dynamic
example of the Original Question is that, in order to be consistent, when types are dynamic we also first find the best overload (checking only parameter number and parameter types etc., not static vs. non-static), and only then check for static.补充:所以我觉得原题的dynamic
例子的解释是,为了保持一致,当类型是动态的时候我们也会先找到最好的重载(只检查参数数量和参数类型等,而不是静态vs.非静态),然后才是检查静态的。 But that means that the static check has to wait until runtime.但这意味着静态检查必须等到运行时。 Hence the observed behavior.因此观察到的行为。
Late addition: Some background on why they chose to do things this funny order can be inferred from this blog post by Eric Lippert .后期补充:可以从Eric Lippert 的这篇博文中推断出他们为什么选择以这种有趣的顺序做事的一些背景。
Foo has a parameter "x" that is dynamic, which means Bar(x) is a dynamic expression. Foo 有一个动态参数“x”,这意味着 Bar(x) 是一个动态表达式。
It would be perfectly possible for Example to have methods like: Example 完全有可能使用以下方法:
static Bar(SomeType obj)
In which case the correct method would be resolved, so the statement Bar(x) is perfectly valid.在这种情况下,将解析正确的方法,因此语句 Bar(x) 是完全有效的。 The fact that there is an instance method Bar(x) is irrelevent and not even considered: by definition , since Bar(x) is a dynamic expression, we have deferred resolution to runtime.有一个实例方法 Bar(x) 的事实是无关紧要的,甚至没有考虑:根据定义,因为 Bar(x) 是一个动态表达式,我们将解析推迟到运行时。
The "dynamic" expression will be bound during runtime, so if you define a static method with the correct signature or a instance method the compiler will not check it. “动态”表达式将在运行时绑定,因此如果您使用正确的签名或实例方法定义静态方法,编译器将不会检查它。
The "right" method will be determined during runtime. “正确”的方法将在运行时确定。 The compiler can not know if there is a valid method there during runtime.编译器无法知道在运行时是否存在有效方法。
The "dynamic" keyword is defined for dynamic and script languages, where the Method can be defined at any time, even during runtime. “dynamic”关键字是为动态和脚本语言定义的,其中方法可以在任何时间定义,甚至在运行时。 Crazy stuff 疯狂的事情
Here a sample which handles ints but no strings, because of the method is on the instance.这是一个处理整数但不处理字符串的示例,因为该方法在实例上。
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++;
}
}
You can add a method to handle all "wrong" calls, which could not be handled您可以添加一个方法来处理所有无法处理的“错误”调用
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++;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.