简体   繁体   English

为什么 C# 编译器不会在静态方法调用实例方法的地方出现错误代码?

[英]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.

相关问题 为什么C#编译器将il代码留给条件方法? - Why does c# compiler leave il code for conditional method? 当最后一个条件调用有条件时,为什么C#编译器会删除方法调用链? - Why does the C# compiler remove a chain of method calls when the last one is conditional? 为什么可以通过类实例在C#中的静态方法中调用非静态方法 - Why calling non-static method inside a static method in C# possible via class instance C#静态方法与对象实例 - C# Static Method vs Object Instance 静态与实例方法性能C# - Static Vs Instance Method Performance C# 为什么C#编译器重载解析算法将具有相同签名的静态和实例成员视为相等? - Why does C# compiler overload resolution algorithm treat static and instance members with equal signature as equal? 为什么没有捕获的lambda从C#5中的静态变为C#6中的实例方法? - Why has a lambda with no capture changed from a static in C# 5 to an instance method in C# 6? C#编译器是否会优化对循环内相同方法的调用? - Will the C# compiler optimize calls to a same method inside a loop? 为什么C#编译器会生成方法调用以在IL中调用BaseClass方法 - Why does C# compiler produce method call to call BaseClass method in IL 为什么C#编译器会在此代码上崩溃? - Why does the C# compiler crash on this code?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM