简体   繁体   中英

C# - Inside instance method, why can we access static members without using the class name?

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?

"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.

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 eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM