This seems counter-intuitive to me. If we have a class Dog with static method CountAllDogs(), C# forbids to call it like this: myDog.CountAllDogs(). (myDog is an object of type Dog). But if we are inside an instance method Bark(), we can call it simply by using CountAllDogs(). Inside the instance method Bark(), the context ("this") is the object myDog, not the class itself, so I wonder why this is allowed?
-
1I assume the compiler is clever enough to know that he doesn´t need an instance for the static member, so adding the class´ name would just be redundant information. Apart from this there is no `this` within a static member. – MakePeaceGreatAgain Sep 20 '17 at 10:46
-
Because the compiler has enough information to unambiguously parse the code and resolve the reference. That's all. – David Sep 20 '17 at 10:49
-
3I think we should invent a word for when people argue for restrictions in a language based on philosophical considerations, rather than whether they would prevent any kind of mistake. It's oddly common. It would make more sense if you argued for `myDog.CountAllDogs()` to be *permitted*, even though it is static -- but here there are probably arguments for overrides, overloads and other things I'm not thinking of that make it sensible for this to be disallowed. – Jeroen Mostert Sep 20 '17 at 10:50
-
@JeroenMostert: The term I often use to describe people who argue about what features a programming language should or should not support is "shouting from the bleachers". I'm guilty of it myself: https://stackoverflow.com/q/16739903/328193 – David Sep 20 '17 at 10:54
-
Perhaps you should read https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/index – Enigmativity Sep 20 '17 at 11:27
-
In what sense is the "context" of the call *not* the class declaration which encloses it? – Eric Lippert Sep 20 '17 at 12:09
-
@EricLippert, I am new to C# so I am trying to clarify the concepts. My remark about the "context" was due to my understanding that all invocations of members inside an instance method have implicit "this" object linked to them. And when "this" equals myDog, it seems strange that it also equals Dog class at the same time... – Jaxx Sep 20 '17 at 12:35
-
@Jaxx: Thanks for explaining why this is confusing to you; that's helpful and interesting to me. – Eric Lippert Sep 20 '17 at 12:36
-
1@Jaxx: The correct way to think about `CallToInstanceMethod()` without `this.` is: first the name is resolved based on the lexical context. Then it is checked to see if it is an instance member; if it is then `this.` is invisibly added for you. If it is not an instance member, then it isn't. Don't think of the *runtime value of this* as being the context. The lexical context is the context. – Eric Lippert Sep 20 '17 at 12:38
-
I think you are also getting a bit confused by the fact that qualified and unqualified name lookup are *completely different beasts*. When you say `foo.Bar`, the lookup for `Bar` is *entirely* dependent on the results of lookup for unqualified `foo`. The rules for looking up `CountAllDogs` in `CountAllDogs()` and the rule for looking up `Dog.CountAllDogs()` are very different. The first one resolves based on lexical scoping. The second is based on the results of the lookup of `Dog`. – Eric Lippert Sep 20 '17 at 12:44
-
@JeroenMostert: Some languages allow qualification of static members with instances; C# does not. The primary reason is that this indicates some fuzzy-headed thinking by the programmer, who might be expecting it to be an instance method, or worse, a virtual method. C#'s basic philosophy in this matter is: bring stuff that looks goofy to the attention of the developer, so that they can resolve it and make the code look right. As you note, there are secondary reasons involving corner cases in the lookup algorithms. – Eric Lippert Sep 20 '17 at 12:47
-
@JeroenMostert: To get a sense of it, try working out something like `class C { public static void M(string)... public void M(object)...} class D { public C C = new C(); public void E() { C.M(""); } }` In the call, is `C` the type or the variable? And is `M` the instance method or the static method? And should it be an error? The compiler has to work stuff like that out, and these rules are complicated enough already. – Eric Lippert Sep 20 '17 at 12:52
-
To expand on Eric's point: A classic example of why qualifying static members on instances is confusing: [Java - Sleeping a thread statically versus using its instance](https://stackoverflow.com/q/5843097/18192) – Brian Sep 20 '17 at 13:36
-
@Brian: the Java example, to me, is better taken as an argument that `Thread.sleep()` is the wrong way to write a method that makes the current thread sleep, than as an argument why calling static methods through the instance should not be allowed. If `sleep()` had been an instance method that throws when not called on the instance that represents the current thread, no confusion would have been possible. It's a static method that has context that is not made explicit through instance data -- that's the real mistake. Even a separate `CurrentThread` static class would improve matters. – Jeroen Mostert Sep 20 '17 at 14:04
2 Answers
"Why" questions are frequently vague, and this one is no exception. Rather than answer your vague and confusing question, I'll answer a different question.
What is the fundamental rule for resolving unqualified names in C#?
The fundamental rule of resolving an unqualified name is search from inside to outside. Suppose you have:
using System;
namespace A {
namespace B {
using C;
class D
{
public static void E() {}
}
class F : D {
public static void G() {}
public void H()
{
Action i = ()=>{};
Now suppose somewhere inside H
we have an unqualified name, X
. We need to figure out what it means. So we go from inside to outside:
- Is there any local variable X? If yes, that's the meaning of X. If not...
- Is there any member of F called X?
- Is there any member of D -- the base class of F -- called X?
- Is there any member of object -- the base class of D -- called X?
- Is there any member of B called X?
- Is there any member of C -- which B is "using" -- called X?
- Is there any member of A called X?
- Is there any member of System called X?
- Is there any global namespace called X?
(This is a sketch that leaves out a few details, such as how aliases are dealt with and so on; read the specification if you want the details.)
An interesting point here is that base classes are considered to be "more inside" than the lexically containing program element. Members of D are considered to be members of F, so they must be checked before we check B.
That's the fundamental rule. There are also a few extra rules added for convenience. For instance, if we had X()
then only invocable members are considered when doing the search. There is also the famous "Color Color" rule, which says that if you have a type called Color and a property of type Color called Color -- because what else would you call it? -- then the name lookup rules for Color are smart about figuring out whether you meant the type or the property, even when that means departing from the fundamental rule of unqualified name lookup.
Now that you know the fundamental rule you can apply it to your situation. Why can you call a static member without qualification? Because the fundamental rule of unqualified name lookup is "search from inside to outside", and doing so finds a static element with that name. If we're inside H
and we have G()
then G
is not a local but it is an invocable member of the enclosing class, so it wins. If we're inside H
and we have E()
then we find it in D
, after failing to find it in H
or F
. And so on.
When you call an unqualified instance member, same thing. The unqualified name is resolved, and if it turns out to be an instance member, then this
is used as the receiver of the member.

- 647,829
- 179
- 1,238
- 2,067
To call an instance-member you need an instance of course. In case you´re allready within an instance-member you can of course use the this
-reference, which points to the current instance. If you´re on the other side calling your instance-member from outside your class you´d write something like this:
myInstance.DoSomething();
So actually using this
as qualifier is redundant, you may simply omit it if you´re within the method.
A static member doesn´t know any instance, thus no this
. Adding the class´-name is again redundant information as adding the this
-keyowrd to an instance-member.
The compiler should be clever enough to determine that a member is static or not and thus if or of not he needs an instance.
Personally I agree that adding the context in which a member might be invoked is a good thing, which is even forced in Java e.g. This avoids anoying prefixes on variables such as m_
for instance- and s_
for static members. But again the compiler allready knows, it´s just a matter of taste.
So having said this there´s no actual need why this should or should not be permitted as it doesn´t avoid any mistakes not produces any. It´s just a convention-thing to be more strict.

- 35,491
- 6
- 60
- 111