Как выполнить некоторый код в суперклассе после того, как все подклассы были созданы? - PullRequest
7 голосов
/ 30 апреля 2010

Есть ли способ сделать это в C #? Я знаю, что подкласс вызовет конструктор суперкласса перед вызовом своего собственного конструктора, но что если у меня есть некоторый код в суперклассе, который должен выполняться только после вызова всех конструкторов подклассов?

Ответы [ 5 ]

3 голосов
/ 30 апреля 2010

Вы могли бы сделать следующее, но это рискованно (см. Мои правки ниже):

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

Редактировать

Как предлагается в комментарии Терренса ниже, это рискованный подход, потому что 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 голосов
/ 30 апреля 2010

Один из способов добиться этого - перейти к двухфазному построению и инициализации. Таким образом, вы создаете экземпляры, а затем вызываете метод initialize, который вызывал базовый класс 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();
  }
}
2 голосов
/ 30 апреля 2010

Нет ничего встроенного в язык C #, который позволял бы вам это делать. Однако использование шаблона создания может поддерживать его. Например, здесь может быть полезен шаблон Abstract Factory Базовая фабрика обеспечит вызов метода во вновь созданном базовом классе, как только он будет создан как конкретный дочерний тип.

0 голосов
/ 30 апреля 2010

Я не уверен, что вы имеете в виду - разве вы не можете просто вызвать код в суперклассе в конце нашего последнего конструктора подкласса? В качестве альтернативы вы можете вызвать его сразу после создания экземпляра.

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
0 голосов
/ 30 апреля 2010
class A : B
{
   public A() : base()
   {
      base.doSomething();
   }
}

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

   }

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

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

Порядок выполнения должен быть:

  1. C :: т е р ()
  2. B :: т е р ()
  3. A :: т е р ()
  4. B :: йоЗотеЬЫпд ()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...