C# 如何更改嵌套构造函数的调用顺序(子级在抽象父级之前)

C# 如何更改嵌套构造函数的调用顺序(子级在抽象父级之前),c#,polymorphism,abstract,C#,Polymorphism,Abstract,下面的代码引发异常,因为在子构造函数之前调用抽象构造函数 我需要提供一个抽象类来封装程序不同部分的一些逻辑。但是,我还需要检查抽象成员是否在创建后正确初始化,而子类对此没有任何影响 下面的编译示例应该说明我的问题 using System; namespace Stackoverflow { class Program { static void Main(string[] args) { var x = new Thin

下面的代码引发异常,因为在子构造函数之前调用抽象构造函数

我需要提供一个抽象类来封装程序不同部分的一些逻辑。但是,我还需要检查抽象成员是否在创建后正确初始化,而子类对此没有任何影响

下面的编译示例应该说明我的问题

using System;

namespace Stackoverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = new Thing(5);
            var y = new Child(x);
        }
    }

    class Child : AbstractParent
    {
        Thing childthing;

        public Child(Thing provided) : base(){
            childthing = provided;
        }

        public override void Initialise(){
            //Exception is thrown here - childthing is still null
            parentthing = childthing.Add(1);
        }
    }

    abstract class AbstractParent
    {
        protected Thing parentthing;

        public AbstractParent(){
            Initialise();
            AssertThingyNotNull();
        }

        private void AssertThingyNotNull(){
            if (parentthing == null) throw new Exception("Waaa");
        }

        public abstract void Initialise();

    }

    class Thing
    {
        private int i;

        public Thing(int i){
            this.i = i;
        }

        public Thing Add(int b){
            i += b;
            return new Thing(i);
        }
    }
}
编辑#1:

有没有一种方法可以做到这一点:向调用者反映(应该是child rigth的创建者?),然后在调用结束时做出反应

编辑#2: 获取创建子对象的.ctor很容易。操纵这些方法似乎是不可能的,也是个坏主意

        foreach (StackFrame frame in new StackTrace().GetFrames())
        {
            Console.WriteLine(frame.GetMethod().Name);
        }

基本上,你不能。这就是为什么您应该尽可能避免从构造函数调用虚拟(或抽象)成员的原因——您可能会得到在不完整的上下文中运行的代码。任何变量初始值设定项都会在调用基类构造函数之前执行,但构造函数体中的任何代码都不会被调用


如果您需要执行初始化,并且只想在派生类构造函数运行时执行初始化,那么只需从派生类构造函数调用
Initialise

基本上您不能。这就是为什么您应该尽可能避免从构造函数调用虚拟(或抽象)成员的原因——您可能会得到在不完整的上下文中运行的代码。任何变量初始值设定项都会在调用基类构造函数之前执行,但构造函数体中的任何代码都不会被调用


如果您需要执行初始化,并且只想在派生类构造函数运行时执行初始化,那么只需从派生类构造函数调用
initialize

您可以执行与Microsoft使用
InitializeComponent()类似的操作。


然后让孩子们随时调用它。

您可以执行类似于Microsoft使用
InitializeComponent()所做的操作。

然后让孩子们随时打电话。

试试这个

编辑=更干净的版本

using System;

namespace ConsoleApplication3
{
class Program
{
    static void Main(string[] args)
    {
        var x = new Thing(5);
        var y = new Child(x);
    }
}

class Child : AbstractParent
{
    public Child(Thing provided)
        : base()
    {
        parentthing = provided;
        base.Initialise();
    }
}

abstract class AbstractParent
{
    protected Thing parentthing;

    public AbstractParent()
    {

    }

    private void AssertThingyNotNull()
    {
        if (parentthing == null) throw new Exception("Waaa");
    }

    public void Initialise()
    {
        AssertThingyNotNull();
    }

}

class Thing
{
    private int i;

    public Thing(int i)
    {
        this.i = i;
    }

    public Thing Add(int b)
    {
        i += b;
        return new Thing(i);
    }
}
}试试这个

编辑=更干净的版本

using System;

namespace ConsoleApplication3
{
class Program
{
    static void Main(string[] args)
    {
        var x = new Thing(5);
        var y = new Child(x);
    }
}

class Child : AbstractParent
{
    public Child(Thing provided)
        : base()
    {
        parentthing = provided;
        base.Initialise();
    }
}

abstract class AbstractParent
{
    protected Thing parentthing;

    public AbstractParent()
    {

    }

    private void AssertThingyNotNull()
    {
        if (parentthing == null) throw new Exception("Waaa");
    }

    public void Initialise()
    {
        AssertThingyNotNull();
    }

}

class Thing
{
    private int i;

    public Thing(int i)
    {
        this.i = i;
    }

    public Thing Add(int b)
    {
        i += b;
        return new Thing(i);
    }
}

}

+1因为“你不能”在形式上是正确的。如果我把草签拿出来,我仍然要调用断言。。。我需要那个断言。@Johannes:好吧,你基本上不能让那个断言作为构造函数的一部分运行。。。如果没有看到真正的代码,就很难知道这里给出的最佳建议,但是如果你能围绕这一点进行设计(例如,使用组合而不是继承),那将非常有帮助。@Jon Skeet-我会考虑的。我的问题只是因为我正在重构。也许我会进行更大规模的重构。@jonskeet-jup你说得对。我将创建打包到一个生成器中,并分离出一个数据对象。问题解决了。+1因为“你不能”在形式上是正确的。如果我把草签拿出来,我仍然要调用断言。。。我需要那个断言。@Johannes:好吧,你基本上不能让那个断言作为构造函数的一部分运行。。。如果没有看到真正的代码,就很难知道这里给出的最佳建议,但是如果你能围绕这一点进行设计(例如,使用组合而不是继承),那将非常有帮助。@Jon Skeet-我会考虑的。我的问题只是因为我正在重构。也许我会进行更大规模的重构。@jonskeet-jup你说得对。我将创建打包到一个生成器中,并分离出一个数据对象。问题已经过去了。啊,我还是不太高兴,因为孩子可以选择不叫init,但我喜欢它,现在就用它。Thx用于编辑代码。啊,我仍然不完全高兴,因为孩子可以选择不调用init-但我喜欢它,现在将使用它。Thx用于编辑代码。我没有在后台运行设计器来确保调用。但我会考虑加入另一个建设者。我没有一个设计师在后台运行,以确保调用。但我会考虑加入另一个建筑商。