【问题标题】:Why a member method of class is called before the Constructor为什么在构造函数之前调用类的成员方法
【发布时间】:2014-12-07 03:05:30
【问题描述】:

一般来说,构造函数是在类中实例化时最先执行的。

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

为什么会这样?

代码场景:

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");
        }
    }
}

【问题讨论】:

  • 您的控制台不会告诉您答案吗?它运行 Abstract 构造函数,然后调用 print 方法......然后它运行派生类构造函数......它几乎不能忽略你放在那里的一些代码。

标签: c# oop inheritance abstract-class


【解决方案1】:

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

这是预期的行为;如果你想让你的类表现不同,你必须改变它们的逻辑。也许你不应该从基础构造函数调用抽象方法,只是为了避免你现在看到的......

【讨论】:

    【解决方案2】:

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

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

    在 C# 中对象构造遵循类层次顺序;也就是说,当调用构造函数时,首先调用最基类的构造函数,然后是立即派生的类构造函数,然后是下一个,依此类推(如果我没记错的话,在 C++ 中它是另一种方式可以导致更多的混乱)。

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

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

    【讨论】:

      【解决方案3】:

      棘手的问题。当您创建这样的对象时

      SavingsCustomer sc = new SavingsCustomer();
      

      它调用Customer[基础类SavingsCustomer]的构造函数,意思是Customer() - 它反过来从类 SavingsCustomer 调用 Print(),因为它在 Customer 类中是抽象的。 尽管它是 SavingsCustomer 的成员函数,但可以在调用 SavingsCustomer 的构造函数之前从 Customer 类调用它,因为 Print() em> 被声明为抽象方法,所以 这两个类共享它。

      下面的声明也是如此

      CorporateCustomer cc = new CorporateCustomer();
      
      CorporateCustomer 类中的

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


      【讨论】:

        猜你喜欢
        • 2012-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-08
        • 2011-12-07
        • 1970-01-01
        • 2015-08-20
        • 2011-02-08
        相关资源
        最近更新 更多