Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么在构造函数之前调用类的成员方法_C#_Oop_Inheritance_Abstract Class - Fatal编程技术网

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

C# 为什么在构造函数之前调用类的成员方法,c#,oop,inheritance,abstract-class,C#,Oop,Inheritance,Abstract Class,通常,构造函数是实例化时在类中执行的第一件事情 但在下面的例子中,首先执行类的一个成员方法&然后是构造函数 为什么会这样 代码场景: namespace AbsPractice { class Program { static void Main(string[] args) { SavingsCustomer sc = new SavingsCustomer(); CorporateCustomer

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

但在下面的例子中,首先执行类的一个成员方法&然后是构造函数

为什么会这样

代码场景:

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()


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

棘手的问题。当你创建这样一个对象时

SavingsCustomer sc = new SavingsCustomer();
它调用Customer的构造函数[类SavingsCustomer的基],表示Customer() -它从类SavingsCustomer调用Print(),因为它在客户类中是抽象的。 尽管它是SavingsCustomer的成员函数,但可以在调用SavingsCustomer的构造函数之前从Customer类调用它,因为Print()被声明为抽象方法,所以它由这两个类共享。

在下面的声明中也会发生同样的情况

CorporateCustomer cc = new CorporateCustomer();
调用CorporateCustomer类中的Print(),因为SavingsCustomer.Print()被重写



除非你有很好的理由,否则你永远不应该这样做

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

在C#中,对象构造遵循类层次顺序;也就是说,当调用构造函数时,最基本的基类构造函数被称为第一个,然后是立即派生的类构造函数,然后是下一个,等等。(如果我没有错的话,C++中的另一个方法会导致更混乱)。 因此,当您从构造函数调用虚拟方法时,真正发生的是,如果虚拟方法被重写(在您的情况下,这是一种保证),那么它将在调用实现类构造函数之前执行。这意味着该方法可以在对象的状态被正确初始化之前执行(通常通过构造函数;如果该方法不依赖于任何对象状态,则该模式不是问题,尽管我仍然不推荐它)


如果绝对有必要使用此模式,好的实践建议实现
Initialize()
方法,并在那里执行任何虚拟调用。强制使用者在使用对象之前调用
初始化
是一项琐碎的任务,您可以保证在进行虚拟调用时对象的状态始终有效。

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