C# 会自动调用基类构造函数吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13166019/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Will the base class constructor be automatically called?
提问by Ivan Li
class Person
{
public int age;
public Person()
{
age = 1;
}
}
class Customer : Person
{
public Customer()
{
age += 1;
}
}
Customer customer = new Customer();
Would the age of customer be 2? It seems like the base class's constructor will be called no matter what. If so, why do we need to call baseat the end sometimes?
顾客的年龄是 2 岁吗?似乎无论如何都会调用基类的构造函数。如果是这样,为什么我们base有时需要在最后调用?
public Customer() : base()
{
.............
}
采纳答案by Tejs
This is simply how C# is going to work. The constructors for each type in the type hierarchy will be called in the order of Most Base -> Most Derived.
这就是 C# 的工作方式。类型层次结构中每种类型的构造函数将按照最基础 -> 最衍生的顺序调用。
So in your particular instance, it calls Person(), and then Customer()in the constructor orders. The reason why you need to sometimes use the baseconstructor is when the constructors below the current type need additional parameters. For example:
因此,在您的特定实例中,它调用Person(), 然后Customer()在构造函数中调用。有时需要使用base构造函数的原因是当前类型下面的构造函数需要额外的参数。例如:
public class Base
{
public int SomeNumber { get; set; }
public Base(int someNumber)
{
SomeNumber = someNumber;
}
}
public class AlwaysThreeDerived : Base
{
public AlwaysThreeDerived()
: base(3)
{
}
}
In order to construct an AlwaysThreeDerivedobject, it has a parameterless constructor. However, the Basetype does not. So in order to create a parametersless constructor, you need to provide an argument to the base constuctor, which you can do with the baseimplementation.
为了构造一个AlwaysThreeDerived对象,它有一个无参数的构造函数。但是,Base类型没有。因此,为了创建无参数构造函数,您需要向基本构造函数提供一个参数,您可以通过base实现来实现。
回答by dasblinkenlight
Yes, the base class constructor will be called automatically. You do not need to add an explicit call to base()when there is a constructor with no arguments.
是的,基类构造函数将被自动调用。base()当存在不带参数的构造函数时,您不需要添加显式调用。
You can easily test this by printing out the age of the customer after construction (link to ideone with a demo).
您可以通过在构建后打印出客户的年龄来轻松测试这一点(链接到 ideone 并带有演示)。
回答by Science_Fiction
If you did not have a default parameterless constructor then there would be a need to call the one with parameters:
如果您没有默认的无参数构造函数,则需要调用带参数的构造函数:
class Person
{
public Person(string random)
{
}
}
class Customer : Person
{
public Customer(string random) : base (random)
{
}
}
回答by steviesama
I don't have much to add, but I have found that I need to call MyConstructor() : base() with no params in 1 case. I have a base class that implements INotifyPropertyChanged in a way where I have a RegisterProperties() virtual function. When I override it, it is called in the base constructor. So I end up having to call it in the most recently derived subclasses because the base was apparently called before the overridden virtual was recognized. My properties don't notify unless I do this. The entire base class is below.
我没有什么要添加的,但我发现我需要在 1 种情况下不带参数调用 MyConstructor() : base() 。我有一个基类,它以我拥有 RegisterProperties() 虚函数的方式实现 INotifyPropertyChanged。当我覆盖它时,它在基础构造函数中被调用。所以我最终不得不在最近派生的子类中调用它,因为在识别覆盖的虚拟之前显然已经调用了基类。除非我这样做,否则我的属性不会通知。整个基类如下。
I added a DatabaseTraits subclass directly below it. Without the empty base() call, my properties don't call OnPropertyChanged().
我在它的正下方添加了一个 DatabaseTraits 子类。如果没有空的 base() 调用,我的属性不会调用 OnPropertyChanged()。
[DataContract]
public abstract class DataModelBase : INotifyPropertyChanged, IDataErrorInfo {
#region Properties
[IgnoreDataMember]
public object Self {
get { return this; }
//only here to trigger change
set { OnPropertyChanged("Self"); }
}
#endregion Properties
#region Members
[IgnoreDataMember]
public Dispatcher Dispatcher { get; set; }
[DataMember]
private Dictionary<object, string> _properties = new Dictionary<object, string>();
#endregion Members
#region Initialization
public DataModelBase() {
if(Application.Current != null) Dispatcher = Application.Current.Dispatcher;
_properties.Clear();
RegisterProperties();
}
#endregion Initialization
#region Abstract Methods
/// <summary>
/// This method must be defined
/// </summar
protected abstract void RegisterProperties();
#endregion Abstract Methods
#region Behavior
protected virtual void OnPropertyChanged(string propertyName) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool RegisterProperty<T>(ref T property, string propertyName) {
//causes problems in design mode
//if (property == null) throw new Exception("DataModelBase.RegisterProperty<T> : ref T property cannot be null.");
if (_properties.ContainsKey(property)) return false;
_properties.Add(property, propertyName);
return true;
}
protected string GetPropertyName<T>(ref T property) {
if (_properties.ContainsKey(property))
return _properties[property];
return string.Empty;
}
protected bool SetProperty<T>(ref T property, T value) {
//if (EqualityComparer<T>.Default.Equals(property, value)) return false;
property = value;
OnPropertyChanged(GetPropertyName(ref property));
OnPropertyChanged("Self");
return true;
}
[OnDeserialized]
public void AfterSerialization(StreamingContext context) {
if (Application.Current != null) Dispatcher = Application.Current.Dispatcher;
//---for some reason this member is not allocated after serialization
if (_properties == null) _properties = new Dictionary<object, string>();
_properties.Clear();
RegisterProperties();
}
#endregion Behavior
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion INotifyPropertyChanged Members
#region IDataErrorInfo Members
string IDataErrorInfo.Error {
get { throw new NotImplementedException(); }
}
string IDataErrorInfo.this[string propertyName] {
get { throw new NotImplementedException(); }
}
#endregion IDataErrorInfo Members
} //End class DataModelBaseclass DataModelBase
/*I decided to add an example subclass*/
[DataContract]
public abstract class DatabaseTraits : DataModelBase {
#region Properties
private long _id = -1;
[DataMember]
public long Id {
get { return _id; }
set { SetProperty(ref _id, value); }
}
private bool _isLocked = false;
[DataMember]
public bool IsLocked {
get { return _isLocked; }
set { SetProperty(ref _isLocked, value); }
}
private string _lockedBy = string.Empty;
[DataMember]
public string LockedBy {
get { return _lockedBy; }
set { SetProperty(ref _lockedBy, value); }
}
private DateTime _lockDate = new DateTime(0);
[DataMember]
public DateTime LockDate {
get { return _lockDate; }
set { SetProperty(ref _lockDate, value); }
}
private bool _isDeleted = false;
[DataMember]
public bool IsDeleted {
get { return _isDeleted; }
set { SetProperty(ref _isDeleted, value); }
}
#endregion Properties
#region Initialization
public DatabaseTraits() : base() {
/*makes sure my overriden RegisterProperties() is called.*/
}
protected override void RegisterProperties() {
RegisterProperty(ref _id, "Id");
RegisterProperty(ref _isLocked, "IsLocked");
RegisterProperty(ref _lockedBy, "LockedBy");
RegisterProperty(ref _lockDate, "LockDate");
RegisterProperty(ref _isDeleted, "IsDeleted");
}
#endregion Initialization
#region Methods
public void Copy(DatabaseTraits that) {
Id = that.Id;
IsLocked = that.IsLocked;
LockedBy = that.LockedBy;
LockDate = that.LockDate;
IsDeleted = that.IsDeleted;
}
#endregion Methods
}
回答by Stokely
In c# using base and derived classes THERE MUST BE SOME IMPLICIT OR EXPLICIT CALL TO SOME CONSTRUCTOR IN THE BASE CLASS FROM THE DERIVED CLASS.
在使用基类和派生类的 c# 中,必须对派生类的基类中的某些构造函数进行一些隐式或显式调用。
I didn't understand how all this worked until I realized that fact.
在我意识到这个事实之前,我不明白这一切是如何运作的。
In other words, when you connect a base class to a derived class, some constructor must be called in the base class from the derived. The base class is always instantiated first from the derived class via a call to some constructor in the base class. C# doesn't care if it is a default constructor or non-default constructor with parameters. That is why you can leave out a default constructor in all your classes as its called implicitly ONLY IF no other non-constructor with parameter(s) is added in the base class.
换句话说,当您将基类连接到派生类时,必须从派生类中调用基类中的某些构造函数。基类总是首先通过调用基类中的某些构造函数从派生类实例化。C# 不关心它是默认构造函数还是带参数的非默认构造函数。这就是为什么您可以在所有类中省略默认构造函数,因为它只有在基类中没有添加其他带有参数的非构造函数时才隐式调用。
When you suddenly add a non-default constructor with parameter(s), it breaks the default hidden default constructor chain creation and calls. In your Base class with a non-default constructor you must now either call that constructor explicitly from the derived class or add a default constructor explicitly in the base class.
当您突然添加带有参数的非默认构造函数时,它会破坏默认隐藏的默认构造函数链的创建和调用。在具有非默认构造函数的基类中,您现在必须从派生类显式调用该构造函数或在基类中显式添加默认构造函数。
Let's test this.....
让我们测试一下这个......
// THIS WORKS!!!
class MyBaseClass0
{
// no default constructor - created automatically for you
}
class DerivedClass0 : MyBaseClass0
{
// no default constructor - created automatically for you and calls the base class default constructor above
}
// THIS WORKS!!!
class MyBaseClass1
{
// same as above
}
class DerivedClass1 : MyBaseClass1
{
public DerivedClass1()
{
// here the derived class default constructor is created explicitly but the call to the base class default constructor is implicitly called
}
}
// AND THIS WORKS!!!
class MyBaseClass2
{
// as above
}
class DerivedClass2 : MyBaseClass2
{
public DerivedClass2() : base()
{
// here we explicitly call the default constructor in the base class using base(). note its optional as base constructor would be called anyway here
}
}
// AND THIS WORKS!!!
class MyBaseClass3
{
// no default constructor
}
class DerivedClass3 : MyBaseClass3
{
public DerivedClass3(int x)//non-default constructor
{
// as above, the default constructor in the base class is called behind the scenes implicitly here
}
}
// AND THIS WORKS
class MyBaseClass4
{
// non default constructor but missing default constructor
public MyBaseClass4(string y)
{
}
}
class DerivedClass4 : MyBaseClass4
{
// non default constructor but missing default constructor
public DerivedClass4(int x) : base("hello")
{
// note that here, we have fulfilled the requirement that some constructor be called in base even if its not default
}
}
// BUT THIS FAILS!!!...until you either add in a base() call to the non-default constructor or add in the default constructor into base!
class MyBaseClass5
{
// 1. EITHER ADD MISSING DEFAULT CONSTRUCTOR HERE AND CALL IT USING base() below....
public MyBaseClass5() { }
// 2. Or use the non-default constructor and call to base("hello") below
//public MyBaseClass5(string y)
//{
//}
}
class DerivedClass5 : MyBaseClass5
{
public DerivedClass5(int x) : base()// 1. Either ADD explicit call here to explicit default constructor in base class
{
}
//public DerivedClass5(int x) : base("hello")// 2. Or ADD explicit call here to parameter-based constructor in base class
//{
//}
}
The reason all the items above work is either: 1. The call to the default constructor in the base class is implicitly created in the base class and implicitly called from the derived because no non-default constructor has been added to the base class or 2. There is an explicit call to non-default , parameter-based constructor using base(myparamter)
上述所有项目工作的原因是: 1. 基类中对默认构造函数的调用是在基类中隐式创建的,并从派生类中隐式调用,因为基类中没有添加非默认构造函数或 2 . 使用 base(myparamter) 显式调用非默认的、基于参数的构造函数
- What's confusing is when and why default constructors get created in base classes and called from derived classes. That only occurs if NO non-default constructors appears in the base.
- 令人困惑的是默认构造函数何时以及为何在基类中创建并从派生类中调用。只有在基类中没有出现非默认构造函数时才会发生这种情况。
回答by Minion
base()is called by default but it can be used for other purpose such as :
base()默认情况下被调用,但它可以用于其他目的,例如:
- base()` method is used to pass the value to the parent class construct or
- to call the no-arg constructor of parent class .
- base()` 方法用于将值传递给父类构造或
- 调用父类的无参数构造函数。
for example:
例如:
Case 1: if parent have parametrized constructor but not default or no-arg constructor.
情况 1:如果父级具有参数化构造函数但没有默认或无参数构造函数。
class Person
{
private string FirstName;
private string LastName;
private string EmailAddress;
private DateTime DateOfBirth;
public Person(string firstName, string lastName, string emailAddress, DateTime dateOfBirth)
{
FirstName = firstName;
LastName = lastName;
EmailAddress = emailAddress;
DateOfBirth = dateOfBirth;
}
}
class Employee : Person
{
private double Salary { get; set; } = 0;
public Employee(string firstName, string lastName, string emailAddress, DateTime dateOfBirth,double salary)
:base(firstName,lastName,emailAddress,dateOfBirth)// used to pass value to parent constructor and it is mandatory if parent doesn't have the no-argument constructor.
{
Salary = salary;
}
}
Case 2: when parent have more than one constructor along with default one.
情况 2:当父级有多个构造函数和默认构造函数时。
class Person
{
private string FirstName;
private string LastName;
private string EmailAddress;
private DateTime DateOfBirth;
public Person()
{
// some important intialization's to be done
}
public Person(string firstName, string lastName, string emailAddress, DateTime dateOfBirth)
{
FirstName = firstName;
LastName = lastName;
EmailAddress = emailAddress;
DateOfBirth = dateOfBirth;
}
}
class PermanentEmployee : Person
{
public double HRA { get; set; }
public double DA { get; set; }
public double Tax { get; set; }
public double NetPay { get; set; }
public double TotalPay { get; set; }
public PermanentEmployee(double hRA, double dA, double tax, double netPay, double totalPay) : base();
{
HRA = hRA;
DA = dA;
Tax = tax;
NetPay = netPay;
TotalPay = totalPay;
}
}
Here we are calling a no-arg constructor manually by base() to perform some intilizations but doesn'e passed any value.
在这里,我们通过 base() 手动调用无参数构造函数来执行一些初始化,但不传递任何值。
Hope this will help you.
希望这会帮助你。

