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用于编辑代码。我没有在后台运行设计器来确保调用。但我会考虑加入另一个建设者。我没有一个设计师在后台运行,以确保调用。但我会考虑加入另一个建筑商。