摘要:C# 初始化方式对比:默认值自动、构造函数显式、对象初始化器简洁,按需选用。
创建类的一个实例时,在执行构造函数之前,如果你没有给成员变量赋初始值,C#编译器缺省将每一个成员变量初始化为它的默认值。
如果变量是方法的局部变量,编译器就会认为在使用该变量之前,代码必须给它显式地设定一个值。否则会发生“使用了未赋值的局部变量”的错误。
对于其他情况,编译器会在创建变量时,把变量初始化为默认值。
1、对于整型、浮点型、枚举类型(数值型),默认值为0或0.0。
2、字符类型的默认值为\x0000。
3、布尔类型的默认值为false。
4、引用类型的默认值为null。
如果声明变量时,为它指定了初始值(int i=10;),那么这个值就用于初始化该变量了。
虽然C#编译器为每个类型都设置了默认值,但作为面向对象的设计原则,我们还是需要对变量进行正确的初始化。实际上这也是C#推荐的做法,没有对变量进行初始化会导致编译器发出警告信息。我们不可能为所有成员变量赋初始值,当然就是赋了值,也不一定就满足我们的要求。因为我们在使用时,有可能改变我们的初始值。那么我们就要借助构造函数来初始化我们的成员变量。
// 系统将为未在构造函数赋值的成员变量赋默认值
using System;
public class Dog
{
public string name;
public int age;
public static void Main()
{
Dog myDog = new Dog();
Console.WriteLine("myDog的名字为“{0}”,年龄为{1}。", myDog.name, myDog.age);
}
}
上述程序中,当创建对象myDog时,会调用默认的构造函数。所有字段都会被赋给一个默认的值。
输出结果为:
myDog的名字为“”,年龄为0。
这种特性虽然能够避免编译错误,但是违背了变量的“先赋值、后使用”原则,这些“无害的”默认值很容易产生难以识别的错误,建议尽可能地在构造函数中对所有成员变量赋值。
下面通过构造函数为 name 和 age 显式赋值,对比默认值初始化的效果:
using System; public class Dog { public string name; public int age; // 带参数的构造函数,为成员变量显式赋值 public Dog(string dogName, int dogAge) { name = dogName; age = dogAge; } public static void Main() { Dog myDog = new Dog("旺财", 3); Console.WriteLine("myDog的名字为“{0}”,年龄为{1}。", myDog.name, myDog.age); } }上述程序中,通过构造函数为 name 和 age 分别赋值为“旺财”和 3,因此输出结果为:
myDog的名字为“旺财”,年龄为3。
对比可见,使用构造函数显式初始化后,成员变量不再使用默认值,而是按照我们的意图被赋予指定值,这更符合“先赋值、后使用”的原则。
| 对比维度 | 默认值初始化 | 构造函数显式初始化 |
|---|---|---|
| name 字段 | 默认为 null(引用类型默认值) | 按传入参数赋值,如“旺财” |
| age 字段 | 默认为 0(整型默认值) | 按传入参数赋值,如 3 |
| 输出结果 | myDog的名字为“”,年龄为0 | myDog的名字为“旺财”,年龄为3 |
| 适用场景 | 字段无特殊要求,可接受默认值 | 需要按业务意图为字段赋予指定初始值 |
对象初始化器(Object Initializer)
除了通过构造函数显式初始化成员变量外,C# 还提供了另一种简洁的初始化方式——对象初始化器。它允许在创建对象实例的同时,直接为可访问的字段或属性赋值,无需编写额外的构造函数重载。
对象初始化器与构造函数显式初始化的主要区别在于使用场景:
- 构造函数显式初始化:适合需要执行复杂逻辑、参数校验或依赖注入的场景,初始化逻辑集中在构造函数中,便于统一管理。
- 对象初始化器:适合仅需为部分字段或属性赋值的简单场景,代码更简洁直观,尤其适合匿名类型和 LINQ 查询中的对象创建。
下面通过对象初始化器为 Dog 类实例赋值,对比构造函数显式初始化的效果:
using System; public class Dog { public string name; public int age; } public class Program { public static void Main() { // 使用对象初始化器为字段赋值 Dog myDog = new Dog { name = "旺财", age = 3 }; Console.WriteLine("myDog的名字为“{0}”,年龄为{1}。", myDog.name, myDog.age); } } // 输出结果: // myDog的名字为“旺财”,年龄为3。可以看到,使用对象初始化器时,无需为 Dog 类编写带参数的构造函数,直接在创建实例的花括号内为 name 和 age 赋值即可,代码更加简洁。当需要初始化的字段较多或初始化逻辑复杂时,仍建议使用构造函数显式初始化。
总结:构造函数显式初始化能按需为成员变量赋予指定值,更符合“先赋值、后使用”的原则,建议在需要明确初始状态的场景下使用。