tips:为什么字段是field
field表示的是一段空间,字段表示的是内存中的一段空间
字段(field)
- 什么是字段
- 字段是一种表示与对象或类型(类与结构体)关联的变量
- 字段是类型的成员
- 与对象关联的字段也称之为“实例字段”:表示实例的某状态
- 与类型关联的字段也称之为“静态字段”,由static修饰:表示类型的某状态
- 字段的声明
- 格式:
[特性] [修饰符]类型 变量声明器;
public int age = 100;//变量声明器是 age=100,age是变量名,=100是初始化器
- 字段的声明不是语句
- 字段的名字一定是名词
- 格式:
- 字段的初始值
- 无显示初始化时,字段获得其类型的默认值,所以字段永远不会被初始化
- 实例字段初始化:对象创建时
- 静态字段初始化:类型被加载时(静态构造器永远只会执行一次)
- 只读字段(readonly)
- 实例只读字段
- 静态只读字段
静态构造器
class Human
{
public static int Age;
static Human()//静态构造器
{
Human.Age = 0;
}
}
属性(C#特有的概念)
- 什么是属性
- 属性是一种用于访问对象或者类型的特征的成员,特征反应了状态
- 属性是字段的自然拓展
- 从命名上来看,field更偏向实例对象在内存中的布局,property更偏向于反映现实世界对象中的特征
- 对外:暴露数据,数据是可以储存在字段里面,也是可以动态计算出来
- 对内:保护字段不会被非法值污染
- 属性由Get/Set方法对进化而来
- 属性背后的秘密(又是一个语法糖)
- 属性的声明
//属性声明的格式是[特性] [修饰符] 类型 成员名称 {访问器} //完整声明和简略声明的区别就在于如何写{访问器}
- 完整声明:
propfull+tab+tab
- 简略声明:
prop+tab+tab
只用于传递数据 - 动态计算值的属性
- 注意实例属性和静态属性
- 属性的名字一定是名词
- 只读属性(几乎没人使用)
- 完整声明:
- 属性和字段的关系
- 一般情况下,它们都是用于表示实体(对象或类型)的状态
- 属性大多数情况下知识字段的包装器
- 建议永远使用属性(而不是字段)来暴露数据,即字段永远都是private或者protected的
属性→字段
将stu3的年龄不小心设置为200,但是平均年龄是80,也符合人的年龄,但是已经为程序引入了一个很难发现的bug,为了避免该情况,可以把Age设置为private,通过Get和Set方法来进行处理
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student();
Student stu2 = new Student();
Student stu3 = new Student();
stu1.Age = 20;
stu2.Age = 20;
stu3.Age = 200;
int avgAge = (stu1.Age + stu2.Age + stu3.Age) / 3;
}
}
class Student
{
public int Age;
}
以下是经过处理的程序
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student();
Student stu2 = new Student();
Student stu3 = new Student();
stu1.SetAge(20);
stu1.SetAge(20);
stu1.SetAge(20);
int avgAge = (stu1.GetAge() + stu2.GetAge() + stu3.GetAge());
Console.WriteLine(avgAge);
}
}
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!");
}
}
}
C#经过改进的写法(添加了value上下文关键字
和set/get访问器
)
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student();
Student stu2 = new Student();
Student stu3 = new Student();
stu1.Age = 20;
stu2.Age = 20;
stu3.Age = 20;
int avgAge = (stu1.Age+stu2.Age+stu3.Age)/3;
Console.WriteLine(avgAge);
}
}
class Student
{
private int age;
public int Age
{
get//get 访问器
{
return this.age;
}
set//set访问器
{
if (value >= 0 && value <= 120)
{
age = value;
}
else
{
throw new Exception("wrong value");
}
}
}
}
探究属性语法糖
使用ildasm(可以去C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\
下找)打开解决方案bin文件夹下的应用程序,展开可以查看最终get和set都是调用了getAge方法
属性的动态计算
CanWork
的值会根据不同的Age
进行不同的更新
class Student
{
private int age;
public int Age
{
get//get 访问器
{
return this.age;
}
set//set访问器
{
if (value >= 0 && value <= 120)
{
age = value;
}
else
{
throw new Exception("wrong value");
}
}
}
public bool CanWork
{
get {
if (this.age >= 16)
{
return true;
}
else
{
return false;
}
}
}
}
索引器(对于初学者很少出现)
- 概念:索引器是这样一种成员:它使对象能够用与数组相同的方式(即使用下标)进行索引,使用快捷键
indexer + tab + tab
- 声明:参见文档,注意没有静态索引器
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
stu["Math"] = 90;
var mathScore = stu["Math"];
Console.WriteLine(mathScore);
}
}
class Student
{
private Dictionary<string, int> scoreDict = new Dictionary<string, int> { };
public int? this[string subject]
{
get {
if (this.scoreDict.ContainsKey(subject))
{
return this.scoreDict[subject];
}
else
{
return null;
}
}
set {
if (value.HasValue == false)
{
throw new Exception("Score can not be null");
}
if (this.scoreDict.ContainsKey(subject))
{
this.scoreDict[subject] = value.Value;
}
else
{
this.scoreDict.Add(subject, value.Value);
}
}
}
}
常量
- 什么是常量
- 常量是表示常量值的类成员
- 常量隶属于类型而不是对象,也就是说没有实例常量(“实例常量的角色由制度字段来承担”)
- 区分成员常量和局部常量
- 常量的声明
- “只读”的应用场景
- 为了提高程序可读性和执行效率-常量
- 为了防止对象的值被更改-只读字段
- 向外暴露不允许修改的数据-只读属性(静态/非静态),功能和常量有一些重叠
- 当希望成为常量的值其类型不能被常量声明接收的时候(类/自定义结构体)-静态只读字段