如何告诉继承类不调用其基类'无参数构造函数?

时间:2010-07-16 14:37:48

标签: c# oop constructor

我很惊讶地发现,无论何时在派生类中调用任何构造函数,都会调用我的基类的无参数构造函数。我认为这是: 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 个答案:

答案 0 :(得分:25)

唯一的方法是明确告诉它你希望它调用哪个其他基地;这当然意味着你必须选择一些基地ctor来打电话。

不能根本没有调用基本ctor - 概念,构建Customer是通过首先构建Person来完成的,然后在其上进行Customer特定构造。例如,假设Personprivate个字段 - 如果Customer的构造允许首先构造Person,那么这些字段将如何正确构建? }?

答案 1 :(得分:8)

在.NET中,无论您是否调用:base(),都将调用对象层次结构中的每个对象构造函数。

如果您没有明确地调用它,则隐式调用

:base()

如果要在父对象上调用不同的构造函数而不是默认构造函数,则可以使用

:base()

如果在父构造函数中有代码,每次都不应该调用它,那么将代码移动到它自己的方法可能会更好,这个方法需要在构造对象后显式调用。或者,在父对象上创建一个参数化构造函数,并使用该参数来确定是否应该执行代码。

例如:

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

答案 2 :(得分:2)

正如其他人所指出的,派生实例必须调用其基类之一的构造函数。

如果要控制基类的初始化逻辑的执行,请删除其默认构造函数并将其替换为以下内容:

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

答案 3 :(得分:0)

一种方法是将您的基本默认构造函数设为私有,但只有在基类中创建一个帮助器构造函数时才会有效,只有在您需要它时才会调用私有构造函数。

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有最好的答案。

答案 4 :(得分:0)

您只需要为某些派生对象调用构造函数的要求不符合面向对象的原则。如果它是一个人,那么它需要这样构建。

如果您需要某些对象的共享初始化,那么您应该考虑创建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)
    {
       // ...
    }
}

答案 5 :(得分:0)

您可以创建默认的基础构造函数protected,然后只为基础及其子项创建非默认构造函数。

修改

您可以为基类提供一个具有不同签名的protected构造函数(例如受保护的枚举类型),并将初始化代码放在那里,而默认构造函数(protected)也不会特别是初始化。

答案 6 :(得分:0)

实例化类时,继承层次结构中的所有类都从最顶层的Parent到最下面的子节点实例化,停止在您实例化的类型上。因此,如果您实例化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.  
   }
}

}