Why does a static hide an overridden method at compile time?

c#

Solution

The following steps seem to happen and are together the reason for your compiler error:

- Step 1: Because of the part from 7.4. you quoted, the instance version of `M` is removed, leaving the compiler only with the static one. The parameter type of the static one is `object`, which is compatible to `int`. The method name matches, too.

- Step 2: Member lookup finished, because a matching method has been found (correct name, compatible parameters), no need to go up the inheritance chain.

- Step 3: Only now is checked if the method is an instance method or a static one.

I can't really quote a single sentence of the spec proving this, but neither §7.4 (Member lookup) nor §3.5 (Accessability) talk about `static` vs. instance, so I assume this fact is simply not taken into account at all when doing a member lookup.

Relevant parts from §7.4 seem to be:

A member lookup of a name N with K type parameters in a type T is processed as follows:

- First, a set of accessible members named N is determined: [...] The set consists of all accessible (§3.5) members named N in T, including inherited members and the accessible members named N in object. If T is a constructed type, the set of members is obtained by substituting type arguments as described in §10.3.2. Members that include an override modifier are excluded from the set.

The way I understand this part it is like explained above: It would return both the instance method and the static one and will then remove the instance one, because it has the `override` modifier. Only the static method is left at this point.

It closes with this:

Finally, [...], the result of the lookup is determined: if the set contains only methods, then this group of methods is the result of the lookup.

So, the result is the static method.

Obviously, this problem only happens in circumstances where you have a class hierarchy and one of the derived classes declares a static method with the same name and compatible parameters.

Adding such a static method to an existing class is a case where simply adding something to a class is still a breaking change.

Although I am pretty sure you know how to solve the compiler error, I will still state it, to have a complete answer: Use any of the base classes as the compile time type of your variable. The runtime type still can be the derived type, that's not the problem:

BaseClass d          = new Derived();
// ^                         ^
// compile time type        runtime type

Problem

Given: ``` class BaseClass { public virtual void M(int x) { } } class Derived : BaseClass { public override void M(int x) { base.M(x); } static void M(object x) { } static void Main() { var d = new Derived(); d.M(0); } } ``` Error: Member 'Derived.M(object)' cannot be accessed with an instance reference; qualify it with a type name instead Looking at the C# 4.0 spec section 7.4 (Member Lookup) the first bullet point reads: A member lookup of a name N with K type parameters in a type T is processed as follows: [...] Members that include an override modifier are excluded from the set [of accessible members named N] From this I conclude that the override `Derived.M` is no longer accessible. Instead, the compiler must refer to `BaseClass.M`. However, this does not explain why adding a static `Derived.M` suddenly causes a compilation error. The compiler can now only see the static member `Derived.M` and concludes that this member is an invalid call. If I remove the static `Derived.M` then compilation succeeds. Why does this happen?

Original source