为什么在构造函数之前调用类的成员方法

本文关键字:成员方法 调用 构造函数 为什么 | 更新日期: 2023-09-27 18:26:14

通常,构造函数是实例化时在类中执行的第一件事。

但在以下情况下,类的A成员方法首先执行&然后是构造函数。

为什么会这样?

代码场景:

namespace AbsPractice
{
    class Program
    {
        static void Main(string[] args)
        {
            SavingsCustomer sc = new SavingsCustomer();
            CorporateCustomer cc = new CorporateCustomer();
        }
    }
    public abstract class Customer
    {
        protected Customer()
        {
            Console.WriteLine("Constructor of Abstract Customer");
            Print();
        }
        protected abstract void Print();
    }
    public class SavingsCustomer : Customer
    {
        public SavingsCustomer()
        {
            Console.WriteLine("Constructor  of SavingsCustomer");
        }

        protected override void Print()
        {
            Console.WriteLine("Print() Method of SavingsCustomer");
        }
    }
    public class CorporateCustomer : Customer
    {
        public CorporateCustomer()
        {
            Console.WriteLine("Constructor of CorporateCustomer");
        }

        protected override void Print()
        {
            Console.WriteLine("Print() Method of CorporateCustomer");
        }
    }
}

为什么在构造函数之前调用类的成员方法

这是因为当您调用SavingsCustomer ctor时,首先调用它的基类ctor;在Customer ctor中,您调用Print,它是一个被重写的方法
因此,基本上在执行SavingsCustomer ctor指令之前,必须完全调用Customer ctor。请注意,当您从Customer调用Print时,会执行SavingsCustomer.Print()

这是预期的行为;如果您希望类的行为有所不同,则必须更改它们的逻辑。也许你不应该从基构造函数调用抽象方法,只是为了避免你现在看到的。。。

除非有充分的理由,否则永远不应该这样做。

从构造函数调用虚拟方法是一场等待发生的灾难。

在C#中,对象构造遵循类层次结构的顺序;也就是说,当调用构造函数时,首先调用最基本的类构造函数,然后调用立即派生的类构造函数、然后调用下一个,等等。

因此,当您从构造函数调用虚拟方法时,实际发生的情况是,如果虚拟方法被重写(在您的情况下,这是一种保证),将在调用实现类构造函数之前执行。这意味着该方法可以在对象的状态被正确初始化之前执行(通常通过构造函数;如果该方法不依赖于任何对象状态,那么这种模式就不是问题,尽管我仍然不建议这样做)。

如果绝对需要使用这种模式,那么良好的实践建议实现Initialize()方法,并在那里执行任何虚拟调用。强制消费者在使用对象之前调用Initialize是一项微不足道的任务,并且您可以保证在进行虚拟调用时对象的状态始终有效。

小问题。当你创建一个像这样的对象时

SavingsCustomer sc = new SavingsCustomer();

它调用Customer[类SavingsCustomer]的构造函数,意思是Customer()-从类SavingsCustomer调用Print(),因为它在Customerclass中是抽象的。尽管它是SavingsCustomer的成员函数,但在调用SavengsCustomerBecuasePrint()的构造函数之前,可以从Customer声明为抽象方法,因此它由这两个类共享

以下声明中也发生了同样的情况

CorporateCustomer cc = new CorporateCustomer();

CorporateCustomer类的Print()被调用,因为SavingsCustomer.Print()被覆盖