【问题标题】:How do I execute some code in a superclass after all the subclasses have been constructed?构造完所有子类后,如何在超类中执行一些代码?
【发布时间】:2011-02-14 09:17:16
【问题描述】:

有没有办法在 C# 中做到这一点?我知道子类会在调用自己的构造函数之前调用超类的构造函数,但是如果我在超类上有一些代码只能在调用所有子类的构造函数后执行呢?

【问题讨论】:

  • 有具体的使用例子吗?

标签: c# .net vb.net oop


【解决方案1】:

实现此目的的一种方法是进行 2 阶段构造并进行初始化。因此,您构造实例,然后调用一个初始化方法,该方法以适当的顺序调用基类 Initialize

class MyBase
{
  // Only if need to do some core initialization
  public MyBase()
  {
  }

  public virtual Initialize()
  {
    // do some initialization stuff here
  }
}

class MyDerived : MyBase
{
  // Only if need to do some core initialization
  public MyDerived()
  {
  }

  public override Initialize()
  {
    // do some initialization stuff here

    // Call the base class initialization function
    base.Initialize();
  }
}

【讨论】:

  • 如果您使用两次创建/初始化,我建议使用工厂方法或 Asbtract Factory 以确保初始化语义不会遍布整个代码。
  • 好吧,这不是我的意思,但它有点帮助我解决问题,ty。
【解决方案2】:

您可以执行以下操作,但这是有风险的(请参阅下面的我的编辑):

public class Parent
{
    public Parent()
    {
        Initialize();
    }

    protected virtual void Initialize()
    {
        // do stuff
    }
}

public class Child : Parent
{
    protected override void Initialize()
    {
        // do child stuff
        base.Initialize();
    }
}

编辑

正如 Terrence 在下面的评论中所建议的,这是一种冒险的方法,因为 Initialize() 将在 Child 的构造函数执行之前执行。如果在Child 的构造函数中初始化了任何字段,如果它们被Initialize() 使用,它们将不会准备好。这可能会导致令人困惑的错误。

一个简单的解决方案是放弃父类调用Initialize(),而是让子类调用Initialize()。正如其他人所建议的那样,另一种选择是使用抽象工厂模式。

这是一个使用静态工厂方法的简单解决方案:

class Program
{
    static void Main()
    {
        Child.Create(() => new Child(5));
        Console.ReadKey();
    }
}

public abstract class Parent
{
    protected virtual void Initialize()
    {
        Console.Write(" is the number.");
    }

    public static TChild Create<TChild>(Func<TChild> childGetter)
        where TChild : Parent
    {
        var child = childGetter();
        child.Initialize();
        return child;
    }
}

public class Child : Parent
{
    private int _number;

    public Child(int number)
    {
        _number = number;
    }

    protected override void Initialize()
    {
        Console.Write(_number.ToString());
        base.Initialize();
    }
}

【讨论】:

【解决方案3】:

C# 语言中没有任何内置功能可让您执行此操作。但是,使用创建模式可以支持它。例如,Abstract Factory 模式在这里可能会有所帮助。一旦新创建的基类被实例化为具体的子类型,基工厂将确保在新创建的基类上调用该方法。

【讨论】:

  • 你知道温莎城堡有没有类似的东西?
  • 这实际上更像是 PostSharp 等 AOP 工具的领域(您现在提醒我应该包含在我的答案中),但温莎可能会这样做。没试过。
【解决方案4】:
class A : B
{
   public A() : base()
   {
      base.doSomething();
   }
}

class B : C
{
   public B() : base()
   {

   }

   public void doSomething() { /* ... */ }
}

class C
{
   public C() { /* ... */ }
}

执行顺序应该是:

  1. C::ctor()
  2. B::ctor()
  3. A::ctor()
  4. B::doSomething()

【讨论】:

  • 我说过,方法应该在超类中执行,而不是在子类中,你只是在子类中调用超类方法。
  • 我怀疑 OP 正在寻找一种解决方案,其中基类可以确保在类型完全实例化后运行一些初始化。否则,每个派生类作者必须确保调用必要的初始化逻辑。
【解决方案5】:

我不确定你的意思 - 你不能在我们最后一个子类构造函数的末尾调用超类中的代码吗?或者,您可以在实例化后直接调用它。

class Program
    {
        static void Main(string[] args)
        {
            SubSub obj = new SubSub();                
            //obj.DoStuff();
            Console.ReadLine();
        }
    }

    class Super
    {
        public Super()
        {
            Console.WriteLine("Constructing Super");
        }
        public void DoStuff()
        {
            Console.WriteLine("Doin' stuff");
        }
    }

    class Sub : Super
    {
        public Sub()
        {
            Console.WriteLine("Constructing Sub");
        }
    }

    class SubSub : Sub
    {
        public SubSub()
        {
            Console.WriteLine("Constructing SubSub");
            DoStuff();
        }
    }

这将输出:

Constructing Super 
Constructing Sub
Constructing SubSub 
Doin' stuff

【讨论】:

  • 我的意思是,代码可以在超类中的对象构建完成后执行,子类不应该知道。
猜你喜欢
  • 2013-07-21
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多