一、字段
什么是字段
- 字段(filed)是一种表示与对象或类型(类或结构体)关联的变量
- 字段是类型的成员,旧称“成员变量”
- 与对象关联的字段亦称“实例字段”
- 与类型关联的字段称为“静态字段”,由 static 修饰
字段的声明
- 参见 C# 语言定义文档
- 尽管字段声明带有分号,但它不是语句
- 字段的名字一定是名词
字段的初始值
- 无显式初始化时,字段获得其类型的默认值,所以字段“永远都不会未被初始化”
- 实例字段初始化的时机——对象创建时
- 静态字段初始化的时机——类型被加载(load)时
只读字段
- 实例只读字段
- 静态只读字段
二、属性
1、什么是属性
- 【1】属性(property)是一种用于访问对象或类型的特征的成员,特征反映了状态
- 【2】属性是字段的自然扩展
- 1)从命名上看,field 更偏向于实例对象在内存中的布局,property 更偏向于反映现实世界对象的特征
- 2)对外: 暴露数据,数据可以是存储在字段里的,也可以是动态计算出来的
- 3)对内: 保护字段不被非法值“污染”
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
Student stu1 = new Student();
stu1.Age = 20;
Student stu2 = new Student();
stu2.Age = 200;
int avgAge = (stu1.Age + stu2.Age) / 2;
Console.WriteLine(avgAge);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
class Student
{
private int age;
public int Age
{
get { return age; }
set
{
if (value > 0 && value <= 120)
{
this.age = value;
}
else
{
throw new Exception("Age value has error.");
}
}
}
}
}
- 【3】属性由 Get/Set 方法对进化而来
- 【4】又一个“语法糖”——属性背后的秘密
2、属性的声明
- 完整声明——后台(back)成员变量与访问器(注意使用 code snippet 和 refactor 工具)
(输入 propfull,按两下Tab,生成如下代码,便是完整声明)
private int myVar;
public int MyProperty
{
get { return myVar; }
set { myVar = value; }
}
- 简略声明——只有访问器(查看 IL 代码)
public int MyProperty { get; set; }
- 动态计算值的属性
class Student
{
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
public bool CanWork
{
get
{
if(this.age >= 16)
{
return true;
}
else
{
return false;
}
}
}
}
- 注意实例属性和静态属性
- 属性的名字一定是名词
- 只读属性——只有 getter 没有 setter
- 尽管语法上正确,几乎没有人使用“只写属性”,因为属性的主要目的是通过向外暴露数据而表示对象/类型的状态
3、属性与字段的关系
- 一般情况下,它们都用于表示实体(对象或类型)的状态
- 属性大多数情况下是字段的包装器(wraper)
- 建议:永远使用属性(而不是字段)来暴露数据,即字段永远都是 private 或 protected 的
三、常量
1、常量的声明和定义
什么是常量
- 常量(constant)是表示常量值(即,可以在编译时计算的值)的类成员
- 常量隶属于类型而不是对象,即没有“实例常量”
- 注意区分成员常量与局部常量
常量的声明
1、各种“只读”的应用场景
- 为了提高程序可读性和执行效率——常量
- 为了防止对象的值被改变——只读字段
- 向外暴露不允许修改的数据——只读属性(静态或非静态),功能与常量有一些重叠
- 当希望成为常量的值其类型不能被常量声明接受时(类/自定义结构体)——静态只读字段
2、和字段不同,属性是一个函数成员。
- 它不一定为数据存储分配内存。
- 它执行代码。
3、属性是一组(两个)匹配的、命名的、称为访问器的方法。
- set 访问器为属性赋值。(有 value 参数和返回类型 void)
- get 访问器从属性获取值。(返回类型 void)
- 属性本身没有任何存储。访问器决定如何处理发送进来的数据,以及将什么数据发送出去。
方法签名
由方法的名称和形参列表组成。具体来说,一个方法的签名由它的名称以及它的形参的个数、修饰符和类型组成。
只读和只写属性
要想不定义属性的某个访问器
- 只有 get 访问器的属性称为只读属性。
- 只有 set 访问器的属性称为只写属性。
- 两个访问器中至少有一个必须定义,否则编译器会产生一条错误消息。
自动属性
静态属性
属性可以声明为 static。静态属性的访问器和所有静态成员一样,具有以下特点。
- 不能访问类的实例成员,但能被实例成员访问。
- 不管类是否有实例,它们都是存在的。
- 在类的内部,可以仅使用名称来引用静态属性。
- 在类的外部,可以通过类名或者使用 using static 结构来引用静态属性。
2、readonly 修饰符
const与readonly 的区别
- const 字段只能在字段的声明语句中初始化,而 readonly 字段可以在下列任意位置设置它的值。
- 字段声明语句,类似于 const。
- 类的任何构造函数、如果是 static 字段,初始化必须在静态构造函数中完成。
- const 字段的值必须可在编译时决定,而 readonly 字段的值可以在运行时决定。这种自由性允许你在不同的环境或不同的构造函数中设置不同的值。
- const 的行为总是静态的,而对于 readonly 字段以下两点是正确的。
- 它可以是实例字段,也可以是静态字段。
- 它在内存中有存储位置。
跟const 区别的用处-例子:
class Shape
{
readonly double PI = 3.1416;
readonly int NumberOfSides;
public Shape(double side1,double side2)
{
NumberOfSides = 4;
}
public Shape(double side1,double side2,double side3)
{
NumberOfSides = 3;
}
}