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

Я был удивлен, узнав, что конструктор без параметров в базовом классе вызывается в любое время, когда я вызываю какой-либо конструктор в производном классе. Я думал, что для этого был : 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);
        }
    }
}

Ответ 1

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

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

Ответ 2

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

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

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

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

Например:

:base(true) - This executes your code.
:base(false) - This does not execute your code.

Ответ 3

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

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

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) {}

Ответ 4

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

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 имеет лучший ответ.

Ответ 5

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

Если вам нужна общая инициализация для некоторых объектов, вам следует подумать о создании метода 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)
    {
       // ...
    }
}

Ответ 6

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

изменить

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

Ответ 7

Когда вы создаете экземпляр класса, все классы в иерархии наследования создаются с самого верхнего родителя до самого нижнего ребенка, останавливаясь на том экземпляре, который вы создали. Поэтому, если вы создаете экземпляр System.Text.StringBuilder(), сначала вы вызываете конструктор по умолчанию для System.Object, а затем StringBuilder(). Вы можете использовать ключевое слово 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.  
   }
}

}