目录
完整声明——后台(back)成员变量与访问器(注意使用code snippet和refactor工具)
字段
什么是字段
-
字段(field)是一种表示与对象或类型(类与结构体)关联的变量,是类型的成员,旧称“成员变量”。
-
与对象关联的字段称“实例字段”。与类型关联的字段称为“静态字段”,由
static
修饰。 -
字段是类中定义的变量,用于存储与类或对象相关的数据。
public class Student
{
// 实例字段
public int Age;
public int Score;
// 静态字段
public static int AverageAge;
public static int AverageScore;
public static int Amount;
// 构造函数
public Student(int age, int score)
{
Age = age;
Score = score;
Amount++;
}
// 静态方法
public static void ReportAmount()
{
Console.WriteLine(Student.Amount);
}
}
实例字段与静态字段的区别
实例字段
- 属于对象级别,每个实例拥有独立副本
- 通过对象实例访问:
student.Age = 20;
- 存储特定实例的状态(如学生的年龄、分数)
静态字段
- 属于类级别,所有实例共享一个副本
- 通过类名访问:
Student.Amount
- 用于存储与整个类相关的信息(如学生总数)
- 在图中构造函数中,每创建一个学生对象就增加计数:
Student.Amount++;
字段的声明
-
参见 C# 语言定义文档。
-
尽管字段声明带有分号,但它不是语句。
-
字段的名字一定是名词。
字段的初始值
-
无显式初始化时,字段获得其类型的默认值,所以字段“永远都不会未被初始化”。
-
实例字段初始化的时机——对象创建时。
-
静态字段初始化的时机——类型被加载(load)时。
只读字段
只读字段(readonly)是一种特殊的字段,其值只能在以下时机设置:
- 在字段声明时
- 在构造函数中
一旦设置后,就不能再被修改,这确保了数据的不可变性。
-
实例只读字段。
- 与特定对象实例相关联
- 可以在实例构造函数中初始化
-
静态只读字段。
- 与类相关联,所有实例共享
- 可以在静态构造函数中初始化
初始化只读字段的两种方式
初始化只读字段有两种主要方式:
- 声明时初始化(使用初始化器)
// 实例只读字段声明时初始化 public readonly int MaxAttempts = 3; // 静态只读字段声明时初始化 public static readonly string CompanyName = "ABC公司";
- 在构造函数中初始化
// 实例只读字段在实例构造函数中初始化 public readonly int MaxAttempts; public MyClass() { MaxAttempts = 3; } // 静态只读字段在静态构造函数中初始化 public static readonly string CompanyName; static MyClass() { CompanyName = "ABC公司"; }
属性
字段+方法=属性
- 属性(property)是一种用于访问对象或类型的特征的成员,特征反映了状态
- 属性是字段的自然扩展,属性的名字一定是名词
属性的特点:
- 从命名上看,field更偏向于实例对象在内存中的布局,property更偏向于反映现实世界对象的特征
- 对外:暴露数据,数据可以是存储在字段里的,也可以是动态计算出来的
- 对内:保护字段不被非法值"污染"
- 属性由Get/Set方法对进化而来
- 又一个"语法糖"——属性背后的秘密
C#中从字段到属性的演进过程
阶段1:直接使用公共字段
class Student
{
private int age; // 私有字段
}
// 使用(但这里实际上使用的是属性,只是代码没完全显示)
stu1.Age = 20;
阶段2:使用Get/Set方法
class Student
{
private int age; // 私有字段
public int GetAge()
{
return this.age;
}
public void SetAge(int value)
{
if (value >= 0 && value <= 120)
{
this.age = value;
}
else
{
throw new Exception("Age value has error.");
}
}
}
// 使用
stu1.SetAge(20);
int avgAge = (stu1.GetAge() + stu2.GetAge() + stu3.GetAge()) / 3;
这种方式的优点:
- 可以添加数据验证逻辑
- 可以控制对字段的访问权限
- 保护字段不被非法值"污染"
缺点:
- 语法繁琐
- 不如直接字段访问那么直观
阶段3:使用C#属性
class Student
{
private int age; // 私有后台字段
public int Age // 公共属性
{
get
{
return this.age;
}
set
{
if (value >= 0 && valu