Как я могу сказать наследующему классу не вызывать конструктора своего базового класса без параметров?

Я был удивлен узнать, что конструктор без параметров моего базового класса позвонился в любое время, я вызываю любого конструктора в производном классе. Я думал именно это : base() был для, для явного вызова основного конструктора, если и когда я хочу.

Как я могу препятствовать тому, чтобы основной конструктор был вызван, когда я инстанцирую производного класса?

using System;

namespace TestConstru22323
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer("Jim", "Smith");
            Customer c = new Customer();
            Console.WriteLine(customer.Display());

            Console.ReadLine();
        }
    }

    public class Person
    {
        public Person()
        {
            Console.WriteLine("I don't always want this constructor to be called. I want to call it explicitly.");
        }
    }

    public class Customer : Person
    {
        private string _firstName;
        private string _lastName;

        //public Customer(string firstName, string lastName): base()  //this explicitly calls base empty constructor
        public Customer(string firstName, string lastName) //but this calls it anyway, why?
        {
            _firstName = firstName;
            _lastName = lastName;
        }

        public string Display()
        {
            return String.Format("{0}, {1}", _lastName, _firstName);
        }
    }
}
11
задан Edward Tanguay 16 July 2010 в 15:04
поделиться

7 ответов

Единственный способ - явно указать ему, какой другой базовый ctor вы хотите, чтобы он вызвал; что, конечно, означает, что вы должны выбрать какой-нибудь базовый ctor для вызова.

Вы не можете заставить его вообще не вызывать базовый ctor - концептуально , создание Customer выполняется путем создания Person , а затем выполняя над ним конструкцию Customer . Например, предположим, что Человек имел закрытые поля - как они будут правильно построены, если при построении Customer было разрешено , а не первое построение a Человек ?

25
ответ дан 3 December 2019 в 02:00
поделиться

Как указывали другие, производный экземпляр должен вызывать один из конструкторов своего базового класса.

Если вы хотите контролировать выполнение логики инициализации базового класса, удалите его конструктор по умолчанию и замените его чем-то вроде этого:

public class Base {
    // Base has no default constructor
    public Base(bool initialize) {
        if (initialize) {
            // ... logic here 
        }
    }    
}

А производные конструкторы выглядят следующим образом:

// Derived1 executes the initialization logic
public Derived1(): base(true) {}

// Derived2 does not
public Derived2(): base(false) {}
2
ответ дан 3 December 2019 в 02:00
поделиться

Вы можете сделать базовый конструктор по умолчанию защищенным , а затем иметь только конструкторы не по умолчанию для базы и ее дочерних элементов.

edit

Вы можете предоставить базе конструктор protected с другой подписью (например, защищенный тип перечисления) и поместить туда свой код инициализации, в то время как конструктор по умолчанию также protected , не требует особой инициализации.

0
ответ дан 3 December 2019 в 02:00
поделиться

Когда вы инстанцируете класс, все классы в иерархии наследования инстанцируются, начиная с самого верхнего родителя до самого нижнего ребенка, останавливаясь на типе, который вы инстанцировали. Так, если вы инстанцируете System.Text.StringBuilder(), сначала вызывается конструктор по умолчанию System.Object, затем StringBuilder(). Вы можете использовать ключевое слово base для вызова другого конструктора (с равными или меньшими параметрами), но не с большим количеством параметров. Если вы не укажете base, будет вызван конструктор по умолчанию, что и является причиной происходящего с вами. Вы также можете использовать ключевое слово base в контексте метода экземпляра для вызова базовых реализаций, как, например, в случае паттерна декоратора. Если вы не хотите вызывать приватные конструкторы базового класса, то вам следует задать дочерним элементам приватные конструкторы по умолчанию, а также явно вызвать base(params) на других конструкторах.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class ProcessCaller
    {
        static void Main()
        {
            MyDerived md1 = new MyDerived(1);
            object o = new System.Text.StringBuilder();//This will implicitly instantiate the classes in the inheritance hierarchy:  object, then stringbuilder
        }
    }

public class MyBase
{
   int num;

   public MyBase() 
   {
      Console.WriteLine("in MyBase()");
   }

   public MyBase(int i )
   {
      num = i;
      Console.WriteLine("in MyBase(int i)");
   }

   public virtual int GetNum()
   {
      return num;
   }
}

public class MyDerived: MyBase
{
   //set private constructor.  base(i) here makes no sense cause you have no params
   private MyDerived()
   {

   }

    // Without specifying base(i), this constructor would call MyBase.MyBase()
   public MyDerived(int i) : base(i)
   {
   }
   public override int GetNum()
   {
       return base.GetNum();//here we use base within an instance method to call the base class implementation.  
   }
}

}
0
ответ дан 3 December 2019 в 02:00
поделиться

Один из способов - сделать ваш базовый конструктор по умолчанию приватным, но это работает только в том случае, если вы создадите вспомогательный конструктор в базовом классе, который будет вызывать приватный конструктор, когда он вам явно понадобится.

class Base
{
  private Base() { ... special default base logic ... }
  protected Base(... params ...) : this() { ... exposed base that calls private cons ... }
  protected Base(... other params ...) /* no default call */ { ... exposed cons that doesnt call default ...}
}

class DerivedNoCall
{
  public DerivedNoCall() : base(... other params ...) {} //<-- will NOT call default base
}

class DerivedDoCall
{
  public DerivedDoCall() : base(... params ...) {} //<-- WILL call default base cons indirectly
}

Это действительно надуманно, и @aakashm имеет лучший ответ.

0
ответ дан 3 December 2019 в 02:00
поделиться

В .NET каждый конструктор объекта в иерархии объектов будет вызываться независимо от того, вызовете ли вы : base ( ) или нет.

: base () вызывается неявно, если вы не вызываете его явно.

: base () можно использовать, если вы хотите вызвать другой конструктор для родительского объекта, а не конструктор по умолчанию.

Если у вас есть код в родительском конструкторе, который не следует вызывать каждый раз, может быть лучше переместить этот код в собственный метод, который необходимо будет вызывать явно после создания объекта. Или создайте параметризованный конструктор для родительского объекта и используйте параметр, чтобы определить, следует ли выполнять код или нет.

Например:

:base(true) - This executes your code.
:base(false) - This does not execute your code.
8
ответ дан 3 December 2019 в 02:00
поделиться

Требование вызова конструктора только для некоторых производных объектов не соответствует объектно-ориентированным принципам. Если это Человек, то он должен быть сконструирован как таковой.

Если вам нужна совместная инициализация для некоторых объектов, вам следует подумать о создании метода Initialize или добавлении параметризованного конструктора, который будет вызываться конкретными производными объектами.

Подход с использованием параметризованного конструктора кажется немного неудобным:

public abstract class Person
{
    protected Person()
    {
    }

    protected Person( bool initialize )
    {
        if (initialize)
        {
            Initialize();
        }
    }

    // ...
}

public class Customer : Person
{
    public Customer(string firstName, string lastName)
    {
       // ...
    }
}

public class Employee : Person
{
    public Customer(string firstName, string lastName) : base(true)
    {
       // ...
    }
}
0
ответ дан 3 December 2019 в 02:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: