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

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

7 ответов


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

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


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

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

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

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

например:

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

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

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

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

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

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

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


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

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

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

}

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

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