CS3L6——成员属性

本章代码关键字

1
2
3
get        //属性中接收值时会执行的关键字
set //属性中被修改值时会执行的关键字
value //属性中set代码块中传入的修改的值

成员属性

属性是 C# 非常好用的语言功能,实际开发中强烈建议使用 公开成员属性 + 私有成员变量 来代替 公开成员变量
因为相比起直接使用公开成员变量,属性具有灵活性,在后续开发可以很方便地对属性读写添加或修改额外逻辑,并提高安全性

成员属性 一般是用来保护成员变量的,成员属性和使用和变量一样 外部用 对象.属性​ 调用
get​ 中需要 return​ 内容;set​ 中用 value​ 表示传入的内容
get​ 和 set​ 语句块内可以加逻辑处理,get和set可以加访问修饰符,但是要按照一定的规则进行添加
get​ 和 set​ 可以只有一个
自动属性是属性语句块中只有 get​ 和 set​,一般用于 外部不能改能得 的情况

属性用于保护成员变量,为成员变量的获取和赋值添加逻辑处理(例如加密等),解决访问修饰符的局限性

  • public​ —— 内外访问
  • private​ —— 内部访问
  • protected​ —— 内部和子类访问

属性可以让成员变量在外部,只能获取不能修改 或者 只能修改不能获取,并为获取和修改添加额外逻辑

成员属性的基本语法

属性的命名一般用帕斯卡命名法

1
2
3
4
5
访问修饰符 属性类型 属性名
{
get { return ... }
set { ... = value }
}

声明示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person
{
private string name;

//属性的命名一般用帕斯卡命名法
public string Name
{
//get需要一个返回值,因此必要return
get
{
//可以在返回之前添加一些逻辑规则,通过属性Name使外部获取到类里私有的name
return name;
}
//set中 value 是关键字 用于表示外部传入的值,使用set需要传入一个值
set
{
//可以在设置之前添加一些逻辑规则
name = value;
}
}
}

如果 get​ 或者 set​ 语句块只有一句代码,则可以使用 =>​ 来简写,=>​ 后跟对应的表达式语句:

1
2
3
4
5
6
7
8
9
10
11
class Person
{
private string name;

//属性的命名一般用帕斯卡命名法
public string Name
{
get => name; //=> 在这里等价于 return,后跟要返回值即可
set => name = value;
}
}

属性的 get​ 或者 set​ 语句块内可以添加多个逻辑,以处理传入的值或者返回的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Person
{
private string name;
private int age;

//属性的命名一般用帕斯卡命名法
public string Name
{
get => name; //等价于 return,=> 后跟要返回值即可
set => name = value;
}

public int Money
{
get => money - 5; //可以解密处理
set
{
//可以保证成员变量处于一个范围内
if (value < 0)
{
value = 0;
WriteLine("钱不能少于0,强制设置为0了");
}
//可以加密,使输入的值在内存中存储不同的加密值
money = value + 5;
}
}
}

成员属性的使用

成员属性本质是类似于只有返回值的或者只有一个参数的方法,因此属性可以如成员变量那样调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Person
{
private string name;
private int age;

public string Name
{
get => name; //等价于 return,=> 后跟要返回值即可
set => name = value;
}

public int Money
{
get => money - 5; //可以解密处理
set
{
//可以保证成员变量处于一个范围内
if (value < 0)
{
value = 0;
WriteLine("钱不能少于0,强制设置为0了");
}
money = value + 5; //可以加密,使输入的值在内存中存储不同的加密值
}
}
}

internal class Program
{
static void Main(string[] args)
{
Person p = new Person();
//因为name是私有的所以我们无法直接修改,但是通过属性Name 我们可以对name进行获取和修改
p.Name = "MrTang"; //下面的语句就执行了属性Name的set语句块
WriteLine(p.Name); //下面的语句就执行了属性Name的get语句块

p.Money = 5; //此时,内存内存储的并不是5,而是10
WriteLine(p.Money); //下面的语句块就执行了get语句块里的解密逻辑
p.Money = -1;
WriteLine(p.Money); //money不能小于0,因此会触发主动写的保护机制
}
}

输出:

1
2
3
4
MrTang
5
钱不能少于0,强制设置为0
0

成员属性中 get 和 set 前可以加访问修饰符

注意

默认不加 会使用属性申明时的访问权限,加的访问修饰符要低于属性的方法权限 (public​ > protected​ > private​)
不能让 get​ 和 set​ 的访问权限都低于属性的权限,否则属性的访问修饰符失去意义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Person
{
private string name;
private int age;

public string Name // 这里的get和set就没有使用访问修饰符,因此默认和Name属性一致,都是public
{
get => name; // 等价于 return,=> 后跟要返回值即可
set => name = value;
}

public int Age
{
private get // 此时,在外部的属性.Age就不能再执行get语句块了,做到了只能修改不能获取
{
return age;
}
set // 这时,set和get不可以都低于属性的访问权限,因此set前不可以加低权限的访问修饰符了
{
age = value;
}
}
}

内部 get​ 和 set​ 的访问修饰符不可高于属性声明用的访问修饰符,
例如,属性本身是 private​ 或 protected​ 的,那么内部 get​ 和 set​ 的访问修饰符就不可以是 public​ 的

成员属性 get 和 set 可以只有一个

当属性只能获取或只能修改时,get​ 和 set​ 可以只有一个,注意,get​ 和 set​ 只有一个时没必要再加访问修饰符了

1
2
3
4
5
6
7
8
9
10
11
12
class Person
{
private bool isSurvive;

public bool IsSurvive //这时就只能得,不能改了,一般情况下都是只有get,很少有只能set的
{
get
{
return isSurvive;
}
}
}

上面的只能 get​ 的属性也被称为只读属性

由于,让外部只能获取而不能修改某个成员变量,又不做额外处理的情况非常多,
因此,属性只有 get​ 且 get​ 语句块只有一句代码时,属性的整个语句块,都可以使用 =>​ 来简写,=>​ 后跟要返回对应的表达式语句

1
2
3
4
5
6
class Person
{
private bool isSurvive;

public bool IsSurvive => isSurvive;
}

自动属性

自动属性是没有特殊处理逻辑,会自动声明并关联成员变量的属性,它关联的成员变量,无需我们去显式声明

1
2
3
4
5
class Person
{
public float Height { get; set; } //自动属性,它会自动生成一个成员变量存储值
public float length { get; private set; } //自动属性,它会自动生成一个成员变量存储值
}

这个自动属性的 get​ 和 set​ 前可以加访问修饰符,也可以只有 get​ (自动属性必须要有 get​),以限制外部的访问和修改

自动属性的好处是可以节约代码量,不需要再申明一个成员变量,
同时解决访问修饰符的局限性,直接用属性解决这个特殊的成员变量需求
这种属性就类似于成员变量,使用该属性会自动生成一个成员变量,而不需要为其申明成员变量

建议仅在 需要解决访问修饰符的局限性(让变量只读) 而又没有别的特殊处理的情况下使用自动属性,不鼓励全部使用自动属性来替代声明成员变量,

注意!自动属性和成员变量本质上不是相同的东西,切勿将两者混为一谈,自动属性在编译后本质上是方法,并管理一个自动生成的变量