为什么在Main函数中总是需要对象引用来调用子类的方法?

Gt_*_*t_R 0 c# inheritance

我想知道为什么在Main方法中总是需要一个对象引用来调用子类的方法.

但是我们可以Main通过其他方法的方法名称直接调用该方法:

using System; 

class MainProgram : Parent_Class 
{
    static void Main(string[] args)
    {
        Project1_Child p = new Project1_Child(); 

        p.PI_add();   //->  Object reference is required     
    }


    public void non_Main_method() 
    {
        PI_add();     //-> No Object reference is required  

    }
}

public class Parent_Class
{


    public void PI_add()
    {

        Console.WriteLine("-------------");

    }

}
Run Code Online (Sandbox Code Playgroud)

为什么是这样?

Eri*_*ert 7

正如其他答案所述,您需要了解静态方法和实例方法之间的区别.这个答案的要点是让你走上正确的术语路径,并考虑调用实例方法.你说:

我想知道为什么在Main方法中总是需要一个对象引用来调用子类的方法.

让我们分解吧.

  • 一个电话是一种成员访问.也就是说,当您拨打电话时,您正在访问某个类型的成员.在这种情况下,您正在访问的成员是方法.
  • 每个会员访问都有一个接收器.接收者是其成员被访问的东西.
  • 旁白:行话"接收器"可能看起来令人困惑,为什么"接收器"?当您访问某个类型的成员时,"收到"了什么?这个术语来自于面向对象编程是关于向对象发送消息然后获得答案的想法.当你打电话时,x = foo.Bar(123)你正在"发送一条消息"来foo了解你想要foo执行的计算,然后foo将结果发回给你x.
  • 不要将接收器视为对象引用."对象"和"引用"在C#中都有非常具体的含义.接收器是一个表达式,类型检查器必须验证它是否具有某些属性.在某些情况下,接收器必须是有效的对象引用,但不是全部,正如我们将看到的那样.
  • 有些成员是"静态的",有些是"实例".不同之处在于:静态成员要求接收者为该类型本身命名.实例成员要求接收者是该类型的实例.
  • 同样,我们有一个行话问题."实例"很明显,但"静态"不是."静态"真的没有充分的理由了; 历史上,静态成员的调用可以通过静态(即编译时)分析来确定.某些实例成员调用由运行时动态调度.VB调用静态方法"共享",这更有意义; 它们在一个类型的实例中"共享".
  • 这里有一个细微之处,因为实例方法的接收者必须是该类型的有效实例.如果接收器是引用类型,那么它必须在运行时评估为非空引用.编译器仅检查编译器是否知道其类型,而不是非空.这可能会在C#8中发生变化!
  • 这里还有另一个细微之处,因为值类型要求接收器不仅仅是一个值,而是一个适当类型的变量.在某些情况下,C#编译器会在必要时为您创建一个变量,但同样,这是一个您可以在以后了解的细微之处.
  • "Elision"是语言研究中的概念,我们可以从句子中"忽略"不必要的单词并仍然理解它们.如果我说"你有什么需要洗的菜吗?" 你会理解这句话,即使在语法上它应该是"需要被洗".
  • 现在我们来到了误解的关键.C#允许您在几种特定情况下忽略接收器.
  • 如果您正在访问的成员是实例成员,并且您是从实例成员访问它,那么您可以忽略接收者,C#将认为您的意思 this.
  • 如果您访问的成员是静态成员,并且您正在从其类的任何成员访问它,那么您可以忽略接收者并且C#将假设您的意思,在这种情况下, MainProgram.

这就解释了你的观察结果.

  • Main你打电话PI_add.这是一个实例成员,所以它需要一个接收器作为实例.如果你是一个实例成员调用,那么C#会假设你已经省略了this.,但是你是从一个静态成员调用的.因此接收器是必需的,忽略接收器是错误的.

  • non_main_method,一个实例方法,你打电话PI_add.这是一个实例方法,因此假设省略了接收者this.

这足以让您走上更高效的道路.当您了解委托和扩展方法时,您会发现这里还有其他细微之处,关于接收器究竟是什么以及编译器如何处理它.