C# 构造函数
最后修改于 2023 年 7 月 5 日
C# 构造函数教程展示了如何在 C# 语言中使用构造函数。
构造函数是在创建对象时调用的方法。类、结构和记录都有构造函数。构造函数的目的是初始化对象的状态。
构造函数不返回值,也不使用 void
关键字。它与类具有相同的名称。构造函数可以被重载;即,可以有多个构造函数(具有相同的名称),但具有不同的参数。
构造函数不能被继承。它们按照继承的顺序被调用。如果我们没有为类编写任何构造函数,C# 会提供一个隐式的默认构造函数。如果我们提供了任何类型的构造函数,则不会提供默认构造函数。
构造函数不能是抽象的、final 的和同步的。
C# 构造函数示例
构造函数用于初始化字段。
var name = "Lenka"; var dob = new DateTime(1990, 3, 5); var u = new User(name, dob); Console.WriteLine(u); class User { private DateTime Born; private string Name; public User(string Name, DateTime Born) { this.Name = Name; this.Born = Born; } public override string ToString() => $"{this.Name} was born on {this.Born.ToShortDateString()}"; }
我们有一个 User
类的构造函数。
var u = new User(name, dob);
我们创建 User
对象,并将其构造函数的两个值传递给它。这是调用对象构造函数的时间。
public User(string Name, DateTime Born) { this.Name = Name; this.Born = Born; }
在构造函数方法中,我们初始化两个属性:Name
和 Born
。由于属性和构造函数参数的名称相同,因此必须使用 this 关键字。它用于引用类的属性。
$ dotnet run Lenka was born on 3/5/1990
如果我们为构造函数参数使用不同的名称,则不需要 this
关键字。
var name = "Lenka"; var dob = new DateTime(1990, 3, 5); var u = new User(name, dob); Console.WriteLine(u); class User { private DateTime Born; private string Name; public User(string _Name, DateTime _Born) { Name = _Name; Born = _Born; } public override string ToString() => $"{this.Name} was born on {this.Born.ToShortDateString()}"; }
由于我们使用了 _Name
和 _Born
构造函数参数名称,它们与 Name
和 Born
属性不同,我们可以省略 this
关键字。
C# 默认构造函数
默认构造函数是不带任何参数的构造函数。
如果我们不提供任何构造函数,C# 默认会创建一个构造函数,它会实例化对象并将成员变量设置为默认值。
var u = new User(); Console.WriteLine(string.IsNullOrEmpty(u.Name)); Console.WriteLine(string.IsNullOrEmpty(u.Occupation)); Console.WriteLine(string.IsNullOrEmpty(u.Dob.ToString())); Console.WriteLine(u); class User { public string Name { get; set; } public string Occupation { get; set; } public DateTime Dob { get; set; } public override string ToString() => $"User {{ {this.Name} {this.Occupation} {this.Dob} }}"; }
我们有一个 User
类;我们没有提供自己的构造函数,因此 C# 创建了一个默认构造函数。 string
数据类型的默认值是空字符串,DateTime
的默认值是 DateTime.MinValue
。
$ dotnet run True True False User { 1/1/0001 12:00:00 AM }
C# 重载构造函数
构造函数可以被重载。
var u1 = new User(); var u2 = new User("Tom"); class User { public User() { Console.WriteLine("User is created"); } public User(string name) { Console.WriteLine($"User {name} is created"); } }
在 User
类中,我们有两个构造函数。 C# 会根据我们传递给它们的参数来调用这些构造函数。
如果我们提供自定义构造函数,C# 不会创建默认构造函数。我们可以显式地创建一个默认的无参数构造函数。
var u1 = new User();
这里,调用了默认的无参数构造函数。
var u2 = new User("Tom");
这里,调用了带有单个参数的第二个构造函数。
$ dotnet run User is created User Tom is created
C# 表达式体构造函数
我们可以创建表达式体构造函数。对于较短的构造函数,它们提供了更简洁且外观更好的语法。
var u1 = new User("John Doe", "gardener"); var u2 = new User("Roger Roe", "driver"); Console.WriteLine(u1); Console.WriteLine(u2); class User { private string Name; private string Occupation; public User(string Name, string Occupation) => (this.Name, this.Occupation) = (Name, Occupation); public override string ToString() => $"User {{ {this.Name} {this.Occupation} }}"; }
我们有一个带有两个参数的构造函数;它们在表达式体中设置。
public User(string Name, string Occupation) => (this.Name, this.Occupation) = (Name, Occupation);
在这种情况下,this
关键字是强制性的。
C# 构造函数链
构造函数链是一个类从一个构造函数调用另一个构造函数的能力。要从同一个类调用另一个构造函数,我们使用 this
关键字。
var c1 = new Circle(5); var c2 = new Circle(); class Circle { public Circle(int radius) { Console.WriteLine($"Circle, r={radius} is created"); } public Circle() : this(1) { } }
我们有一个 Circle
类。该类有两个构造函数:第一个带有单个参数,第二个不带任何参数。
public Circle(int radius) { Console.WriteLine("Circle, r={0} is created", radius); }
此构造函数接受一个参数 - radius
。
public Circle() : this(1) { }
这是不带参数的构造函数。它只是调用另一个构造函数并为其提供默认半径 1。
$ dotnet run Circle, r=5 is created Circle, r=1 is created
C# 基类构造函数
当实例化派生类时,会自动调用基类构造函数。
var u1 = new User(); Console.WriteLine("---------------"); var u2 = new User("Tom"); class Base { public Base() { Console.WriteLine("Base constructor called"); } } class User : Base { public User() { Console.WriteLine("User constructor called"); } public User(string user) { Console.WriteLine($"User {user} created"); } }
User
类继承自 Base
类。两个构造函数都调用基类构造函数。
$ dotnet run Base constructor called User constructor called --------------- Base constructor called User Tom created
使用 base
关键字,我们可以指定在创建派生类实例时应调用哪个基类构造函数。
var u1 = new User(); Console.WriteLine("---------------"); var u2 = new User("Tom"); class Base { public Base() { Console.WriteLine("Base() called"); } public Base(string name) { Console.WriteLine("Base(string name) called"); } } class User : Base { public User() { Console.WriteLine("User created"); } public User(string name) : base(name) { Console.WriteLine($"User {name} created"); } }
现在 Base
类有两个构造函数。我们可以使用 base
关键字指定要调用的构造函数。
public User(string name) : base(name) { Console.WriteLine($"User {name} created"); }
我们告诉构造函数调用带有单个参数的基类构造函数。
$ dotnet run Base() called User created --------------- Base(string name) called User Tom created
C# 复制构造函数
通过从另一个对象复制变量来创建对象的构造函数称为复制构造函数。
var u1 = new User("John Doe", "gardener"); var u2 = new User(u1); u2.Name = "Roger Roe"; Console.WriteLine(u1); Console.WriteLine(u2); class User { public string Name { get; set; } public string Occupation { get; set; } public User(string Name, string Occupation) => (this.Name, this.Occupation) = (Name, Occupation); public User(User user) { this.Name = user.Name; this.Occupation = user.Occupation; } public override string ToString() => $"User {{ {this.Name} {this.Occupation} }}"; }
User
类包含一个复制构造函数。
public User(User user) { this.Name = user.Name; this.Occupation = user.Occupation; }
类的属性从作为参数传递给构造函数的对象中赋值。
$ dotnet run User { John Doe gardener } User { Roger Roe gardener }
C# 私有构造函数
其他类无法创建仅具有私有构造函数的类的实例。私有构造函数通常用于仅具有静态成员的类中。
Console.WriteLine(MyMath.Pow(2)); Console.WriteLine(MyMath.Pow(2, 3)); Console.WriteLine(MyMath.Pow(2, 5)); // var mm = new MyMath(); // Console.WriteLine(mm.GetType()); class MyMath { private MyMath() { } public static int Pow(int x, int y = 2) { int val = 1; for (int i = 0; i < y; i++) { val *= x; } return val; } }
我们有一个 MyMath
类,它包含一个唯一的静态成员。它的设计目的是在不创建其实例的情况下使用 - 私有构造函数禁止这样做。
$ dotnet run 4 8 32
C# 静态构造函数
静态构造函数用于初始化静态数据或执行只需要执行一次的操作。它在创建第一个实例或引用任何静态成员之前自动调用。
var runner1 = new Runner(1); Thread.Sleep(700); var runner2 = new Runner(2); Thread.Sleep(1100); Console.WriteLine(runner1.Finish()); Console.WriteLine(runner2.Finish()); class Runner { private static readonly DateTime StartTime; private long Id; static Runner() => StartTime = DateTime.Now; public Runner(long Id) => this.Id = Id; public string Finish() { DateTime EndTime = DateTime.Now; return $"Runner {this.Id} finished in {EndTime - StartTime}"; } }
我们有一个静态只读变量,名为 StartTime
。当第一个 Runner
被创建时,它使用静态构造函数进行初始化。
static Runner() => StartTime = DateTime.Now;
一旦初始化,静态 StartTime
可用于 Runner
的所有实例。
$ dotnet run Runner 1 finished in 00:00:01.8267889 Runner 2 finished in 00:00:01.8900243
来源
在本文中,我们使用了 C# 中的构造函数。
作者
列出所有 C# 教程。