从`new()`到`.DoSomething()`:一篇讲透C#方法与构造函数的终极指南
一、构造函数(Constructor)
构造函数是一个特殊的方法,它的唯一使命就是在创建一个类的实例时执行初始化操作。它确保了对象在被使用之前,处于一个有效的、可预期的初始状态。
1. 构造函数的特征
- 名称必须与类名完全相同。
-
没有返回类型,甚至连
void都不能写。 - 通常被声明为
public,以便外部代码可以创建类的实例。
2. 默认构造函数
如果你在类中不定义任何构造函数,C#编译器会为你提供一个隐藏的、无参数的默认构造函数。
public class Robot
{
public string Model;
}
// === 使用 ===
Robot r1 = new Robot(); // 编译器提供的默认构造函数被调用
// 此时 r1.Model 的值是其类型默认值,即 null
但只要你定义了任何一个构造函数,编译器就不会再为你提供默认构造函数了。
3. 带参数的构造函数
它强制调用者在创建对象时,必须提供必要的初始数据。
public class Robot
{
public string Model { get; } // 设置为只读,体现其一旦设定就不应改变的特性
public DateTime ProductionDate { get; }
// 这是一个带参数的构造函数
public Robot(string model)
{
// 验证输入
if (string.IsNullOrWhiteSpace(model))
{
throw new ArgumentException("机器人型号不能为空。");
}
this.Model = model;
this.ProductionDate = DateTime.UtcNow; // 记录生产日期
Console.WriteLine($"型号为 {this.Model} 的机器人已生产!");
}
}
// === 使用 ===
Robot terminator = new Robot("T-800"); // 必须提供型号
// Robot r2 = new Robot(); // 编译错误!因为定义了有参构造,默认的无参构造消失了。
4. 构造函数重载
一个类可以有多个构造函数,只要它们的参数列表不同即可。
参数列表不同可以是:
- 类型不同
- 数量不同
- 顺序不同
public class Robot
{
public string Model { get; }
public string Owner { get; set; }
// 主构造函数,逻辑最完整
public Robot(string model, string owner)
{
this.Model = model;
this.Owner = owner;
}
// 重载1:只提供型号,主人默认为 "Cyberdyne Systems"
public Robot(string model)
{
this.Model = model;
this.Owner = "Cyberdyne Systems";
}
}
5.构造函数链 (this关键字)
上面的重载代码有重复(this.Model = model;)。当初始化逻辑很复杂时,这种重复会导致维护困难。我们可以使用this关键字,让一个构造函数去调用同一个类中的另一个构造函数。
public class Robot
{
public string Model { get; }
public string Owner { get; set; }
// 主构造函数
public Robot(string model, string owner)
{
this.Model = model;
this.Owner = owner;
}
// 使用 : this(model, "Cyberdyne Systems")
// 表示在执行这个构造函数的函数体之前,
// 先去调用那个匹配签名的构造函数 Robot(string, string)
public Robot(string model) : this(model, "Cyberdyne Systems")
{
// 这里可以留空,或者只写真正属于这个构造函数的特殊逻辑
Console.WriteLine("一个无主机器人被生产...");
}
}
6. 静态构造函数
普通构造函数在new对象时执行,用于初始化实例成员。而静态构造函数在类首次被访问时(如创建第一个实例、或调用静态成员)由.NET运行时自动调用,且只执行一次,用于初始化静态成员。
public class RobotFactory
{
// 静态字段
private static readonly string _factoryLocation;
// 静态构造函数
static RobotFactory()
{
// 用于初始化静态数据,比如从配置文件读取信息
_factoryLocation = "California";
Console.WriteLine("机器人总工厂启动!只启动一次。");
}
}
// === 使用 ===
var f1 = new RobotFactory(); // 首次访问类,静态构造函数执行
var f2 = new RobotFactory(); // 不再执行静态构造函数
二、方法(Method
1. 方法的基本语法
// 访问修饰符 返回类型 方法名(参数列表)
// {
// 方法体...
// }
public void Walk(int steps)
{
Console.WriteLine($"机器人向前走了 {steps} 步。");
}
-
返回类型:如果方法执行完毕后需要返回一个结果,就指定其类型(
int,string,bool等)。如果不需要,就使用void。 - 参数列表:定义了调用该方法时需要传入的数据。
2. 方法重载
与构造函数一样,方法也可以被重载。只要方法名相同,但参数列表不同即可。
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
// 重载:接受三个整数
public int Add(int a, int b, int c)
{
return a + b + c;
}
// 重载:接受两个双精度浮点数
public double Add(double a, double b)
{
return a + b;
}
}
3.参数的特殊标识:out, ref, params
-
out参数:返回多个值out参数用于从方法中传出数据。它要求方法内部必须为其赋值。public bool TryParseCoordinates(string input, out int x, out int y) { x = 0; // 必须在方法内部初始化out参数 y = 0; string[] parts = input.Split(','); if (parts.Length == 2 && int.TryParse(parts[0], out x) && int.TryParse(parts[1], out y)) { return true; } return false; } // === 使用 === string data = "10,20"; if (TryParseCoordinates(data, out int lat, out int lon)) { Console.WriteLine($"解析成功: X={lat}, Y={lon}"); } -
ref参数:按引用传递 默认情况下,值类型(如int,struct)参数是按值传递的(复制一份)。使用ref可以让方法直接操作原始变量。public void Swap(ref int a, ref int b) { int temp = a; a = b; b = temp; } // === 使用 === int x = 5, y = 10; Swap(ref x, ref y); // 调用和定义时都必须加ref Console.WriteLine($"x={x}, y={y}"); // 输出: x=10, y=5 -
params参数:可变数量的参数params允许你向方法传入任意数量的同类型参数。它必须是方法参数列表中的最后一个。public int Sum(params int[] numbers) { int total = 0; foreach (int num in numbers) { total += num; } return total; } // === 使用 === int sum1 = Sum(1, 2, 3); int sum2 = Sum(5, 10, 15, 20, 25);
三、静态方法static
static关键字既可以修饰字段/属性,也可以修饰方法和构造函数。它划出了一条清晰的界线:属于对象实例的,还是属于类本身的。
-
实例方法(无
static):- 属于某个具体的对象。
- 必须通过对象实例来调用。
- 可以访问该对象的实例成员和静态成员。
-
静态方法(有
static):- 属于类本身,不属于任何具体对象。
- 必须通过类名来调用。
- 不能访问任何实例成员(因为它不知道你想操作哪个对象),只能访问其他静态成员。
public class Robot
{
public string Model { get; } // 实例成员
public static int TotalRobotsProduced { get; private set; } // 静态成员
public Robot(string model)
{
this.Model = model;
TotalRobotsProduced++; // 实例构造函数可以访问静态成员
}
// 实例方法
public void AnnounceModel()
{
// 可以访问实例成员Model和静态成员TotalRobotsProduced
Console.WriteLine($"我是 {this.Model}。目前共生产了 {TotalRobotsProduced} 台机器人。");
}
// 静态方法
public static void PrintFactoryInfo()
{
// 不能访问 this.Model (编译错误)
Console.WriteLine($"这是一个机器人制造工厂。已生产 {TotalRobotsProduced} 台机器人。");
}
}
// === 使用 ===
Robot.PrintFactoryInfo(); // 通过类名调用静态方法
Robot r1 = new Robot("R2-D2");
r1.AnnounceModel(); // 通过实例调用实例方法
Robot r2 = new Robot("C-3PO");
r2.AnnounceModel();
Robot.PrintFactoryInfo(); // 静态成员的值被所有实例共享和更新
结语
点个赞,关注我获取更多实用 C# 技术干货!如果觉得有用,记得收藏本文!