C# - 内部实例方法,为什么我们可以在不使用类名的情况下访问静态成员?

时间:2017-09-20 10:43:26

标签: c#

这对我来说似乎是违反直觉的。如果我们有一个带有静态方法CountAllDogs()的类Dog,C#禁止这样调用它:myDog.CountAllDogs()。 (myDog是Dog类型的对象)。 但是如果我们在实例方法Bark()中,我们可以通过使用CountAllDogs()来调用它。在实例方法Bark()中,上下文(“this”)是对象myDog,而不是类本身,所以我想知道为什么允许这样做?

2 个答案:

答案 0 :(得分:6)

“为什么”这些问题经常含糊不清,而且这个问题也不例外。我会回答一个不同的问题,而不是回答你模糊而混乱的问题。

  

在C#中解析不合格的名称的基本规则是什么?

解决不合格名称的基本规则是从内到外搜索。假设你有:

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 = ()=>{};

现在假设H内的某个地方有一个不合格的名字X。我们需要弄清楚它意味着什么。所以我们从内到外:

  • 是否有局部变量X?如果是,那就是X的意思。如果不是......
  • F的成员是否有X?
  • 是否有D的成员 - F的基类 - 称为X?
  • 是否有任何对象成员--D的基类 - 称为X?
  • B的成员是否有X?
  • 是否有C的成员 - 哪个B是“正在使用” - 称为X?
  • 是否有任何一个叫做X的成员?
  • 是否有任何系统成员名为X?
  • 是否有任何名为X的全局命名空间?

(这是一个草图,省略了一些细节,例如如何处理别名等等;如果你想要详细信息,请阅读规范。)

这里有一个有趣的观点是,基类被认为比含有词法的程序元素更“内部”。 D的成员被认为是F的成员,所以在我们检查B之前必须检查

这是基本规则。为方便起见,还添加了一些额外的规则。例如,如果我们有X(),那么在进行搜索时只会考虑可调用的成员。还有着名的“颜色颜色”规则,它表示如果你有一个名为Color的类型和一个名为Color的Color类型的属性 - 因为你还有什么叫它呢? - 然后,Color的名称查找规则很明智,无论是否意味着您的类型或属性,即使这意味着偏离了非限定名称查找的基本规则。

现在您已了解基本规则,您可以将其应用于您的情况。为什么你可以没有资格打电话给静态会员?因为非限定名称查找的基本规则是“从内到外搜索”,并且这样做找到具有该名称的静态元素。如果我们在H内,并且我们有G(),那么G不是本地的,但它是封闭类的可调用成员,因此它获胜。如果我们在H内,并且我们E(),那么我们会在DH中找不到它后在F找到它。等等。

当您调用不合格的实例成员时,同样的事情。解析了非限定名称,如果结果是实例成员,则,然后this用作成员的接收者。

答案 1 :(得分:1)

要调用实例成员,您需要一个实例。如果您已经实例成员中,您当然可以使用this - 引用,它指向当前实例。如果你在另一边从你的课外调用你的实例成员,你会写下这样的东西:

myInstance.DoSomething();

所以实际使用this作为限定符是多余的,如果你方法中,你可以简单地省略它。

静态成员不知道任何实例,因此没有this。添加class'-name再次是将this - keyowrd添加到实例成员的冗余信息。

编译器应该足够聪明,以确定成员是否是静态的,因此他是否需要实例。

我个人同意添加可以调用成员的上下文是一件好事,甚至在Java中强制使用,例如这样可以避免对变量(如m_例如 - 和s_)的静态成员使用前缀。但是编译器已经知道了,这只是一个品味问题。

所以说这没有实际的需要为什么这应该或不应该被允许,因为它不会避免任何错误而不会产生任何错误。这只是一个更严格的惯例。