简体   繁体   English

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

[英]How can I tell the inheriting class to not call its base class' parameter-less constructor?

I was surprised to find out that the parameter-less constructor of my base class is called any time I call any constructor in a derived class. 我很惊讶地发现,无论何时调用派生类中的任何构造函数,都会调用我的基类的无参数构造函数。 I thought that is what : base() was for, to explicitly call the base constructor if and when I want to. 我认为这就是: base()用于显式调用基本构造函数,如果我想要的话。

How can I prevent the base constructor from being called when I instantiate a derived class? 在实例化派生类时,如何防止调用基本构造函数?

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

The only way is to explicitly tell it which other base ctor you want it to call; 唯一的方法是明确告诉它你想要它调用哪个其他基地; which of course means you must choose some base ctor to call. 这当然意味着你必须选择一些基本的ctor来打电话。

You can't have it call no base ctor at all - conceptually , constructing a Customer is done by first constructing a Person , and then doing Customer specific construction on top of it. 根本不能称之为基础ctor - 概念上 ,构建Customer是通过首先构建一个Person ,然后在它之上进行Customer特定的构建来完成的。 For example, suppose Person had private fields - how would these be correctly constructed if construction of a Customer was allowed to not first construct a Person ? 例如,假设Personprivate字段 - 如果允许构建Customer 首先构造Person那么这些字段将如何正确构造?

In .NET, every object constructor in an object hierarchy will be called regardless if you call :base() or not. 在.NET中,无论您是否调用:base() ,都将调用对象层次结构中的每个对象构造函数。

:base() is implicitly called if you don't explicitly call it. :base()如果没有显式调用它,则会隐式调用:base()

:base() can be used if you want to call a different contructor on a parent object rather than the default constructor. 如果要在父对象上调用不同的构造函数而不是默认构造函数,则可以使用:base()

If you have code in the parent constructor that should not be called everytime, it may be better to move that code to it's own method that will need to be called explicitly after the object is constructed. 如果你的父构造函数中的代码每次都不应该调用,那么将代码移动到它自己的方法可能会更好,这种方法需要在构造对象后显式调用。 Or, create a parameterized constructor on the parent object and use the parameter to determine if the code should be executed or not. 或者,在父对象上创建一个参数化构造函数,并使用该参数来确定是否应该执行代码。

For example: 例如:

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

As others have pointed out, a derived instance must call call one of its base class' constructors. 正如其他人所指出的,派生实例必须调用其基类之一的构造函数。

If you want to control the execution of a base class' initialization logic, remove its default constructor and replace it with something like this: 如果要控制基类的初始化逻辑的执行,请删除其默认构造函数并将其替换为如下所示:

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

And the derived constructors look like this: 派生的构造函数看起来像这样:

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

// Derived2 does not
public Derived2(): base(false) {}

One way would be to make your base default constructor private, but that only works if you make a helper constructor in the base class that calls the private one when you need it explicitly. 一种方法是使您的基本默认构造函数成为私有,但只有在基类中创建一个帮助器构造函数时才会有效,只有在您明确需要它时才调用私有构造函数。

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
}

This is really contrived, and @aakashm has the best answer. 这是非常人为的, @ aakashm有最好的答案。

Your requirement to only need to call the constructor for some derived objects is not in line with the object-oriented principles. 您只需要为某些派生对象调用构造函数的要求不符合面向对象的原则。 If it's a Person, then it needs to be constructed as such. 如果它是一个人,那么它需要这样构建。

If you need shared initialization for some objects, then you should consider creating an Initialize method or adding a parameterized constructor that will be called by the specific derived objects. 如果需要对某些对象进行共享初始化,则应考虑创建Initialize方法或添加将由特定派生对象调用的参数化构造函数。

The parameterized constructor approach feels a little awkward: 参数化的构造函数方法感觉有点尴尬:

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

You could make the default base constructor protected , then have only non-default constructors for the base and its child. 您可以使默认基本构造函数protected ,然后只为基础及其子项创建非默认构造函数。

edit 编辑

You could give the base a protected constructor with a different signature (such as a protected enum type), and put your initialization code in there, while the default constructor, also protected , does not particular initialization. 您可以为基类提供具有不同签名的protected构造函数(例如受保护的枚举类型),并将初始化代码放在那里,而默认构造函数也protected ,不会进行特定的初始化。

When you instantiate a class all the classes in the inheritance hierarchy are instantiated starting from the topmost Parent to the lowermost child, stopping at the type you instantiated. 实例化类时,继承层次结构中的所有类都从最顶层的Parent到最下面的子节点进行实例化,停止在您实例化的类型上。 So if you instantiate System.Text.StringBuilder(), first you call the default constructor of System.Object, then StringBuilder(). 因此,如果您实例化System.Text.StringBuilder(),首先调用System.Object的默认构造函数,然后调用StringBuilder()。 You can use the base keyword to call a different constructor (one with equal or fewer params), but not more params. 您可以使用base关键字来调用不同的构造函数(一个具有相同或更少的参数),但不能使用更多的参数。 If you do not specify base, the default constructor is called, thus the reason this is happening to you. 如果未指定base,则会调用默认构造函数,因此会发生这种情况。 You can also use the base keyword within the context of an instance method to call base implementations, such as in the case of the decorator pattern. 您还可以在实例方法的上下文中使用base关键字来调用基本实现,例如在装饰器模式的情况下。 If you do not want to call the base class private constructors then you should set the children with private default constructors and also explicitly call base(params) on your other constructors. 如果您不想调用基类私有构造函数,那么您应该使用私有默认构造函数设置子项,并在其他构造函数上显式调用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.  
   }
}

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在基类中使用带有无参数构造函数的Activator创建Class的实例 - Create instance of Class using Activator with parameter-less constructor in base class 继承类并调用隐藏的基础构造函数 - Inheriting class and call hidden base constructor WCF / Ninject /默认(无参数)构造函数 - WCF / Ninject / Default (parameter-less) constructor 继承基构造函数参数<summary>在派生类 C# - Inheriting base constructor parameter <summary> in a derived class C# 如何避免继承的类必须传递基类的构造函数参数 - How can I avoid that the inherited class have to pass the base class constructor parameter 如果派生类没有参数化构造函数,如何从派生类中调用基类的参数化构造函数? - How can I call a base class's parameterized constructor from a derived class if the derived class has no parameterized constructor? 基类构造函数参数 - Base class constructor parameter 如何在派生类中调用基类构造函数? - How to call base class constructor in derived class? 如何强制继承类在其构造函数中实现方法? - How to force an inheriting class to implement a method in its constructor? 如何在没有默认的无参数构造函数的情况下为单个WCF服务注入参数 - How to inject parameters for a Single WCF Service without the default parameter-less constructor
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM