C#学习笔记 -- 类的属性
属性
属性代表类实例或类中数据项的成员, 使用属性就像写入或读取一个字段, 语法相同, 从语法上无法区分他们
(0)属性的特征
-
是命名的类成员
-
有类型
-
可以被赋值和读取
-
与字段不同, 属性是一个函数成员
-
不一定为数据存储分配内存
-
-
-
属性是两个匹配的、命名的、称为访问器的方法,访问器不能直接被调用
-
set访问器给属性赋值
-
get访问器获取属性值
-
(1)属性声明与访问器
//声明类一个名为MyValue的int类型属性的语法 int MyValue { set { //SetAccessorCode } get { //GetAccessorCode return intValue; } }
-
set和get访问器有预订的语法和语义, 而且可以以任何顺序声明, 除了这两个访问器外, 属性上不允许有其他方法
-
可以把set访问器想象成一个方法, 带有单一的参数, 他设置属性的值
-
set访问器有一个单独的隐式的值参, 名称为value, 与属性的类型相同, 无需再声明参数列表的值参数
-
set访问器返回void
-
-
get访问器没有参数, 并从属性返回一个值
-
get访问器没有参数
-
隐式的拥有一个与属性类型相同的返回类型, 无需再声明返回值
-
get访问器的所有执行路径必须包含一条返回语句, 将返回一个属性类型的值
-
(2)创建属性示例
注意
-
属性自己并没有任何存储, 取而代之, 访问器决定如何处理发送进来的数据, 以及将什么数据发送出去,
-
属性访问器常常使用字段作为存储
-
set访问器接受它的输入参数value, 并把它的值赋给字段theRealValue
-
get访问器只是返回字段的值TheRealValue
class Program710_2 { private int theRealValue; public int MyValue { set { theRealValue = value; } get { return theRealValue; } } }
(3)使用属性
写入和读取属性的方法与访问字段一样, 访问器被隐式调用
-
要写入一个属性, 在赋值语句的左边使用属性的名称, 不能显式调用set访问器
-
要读取一个属性, 把属性的名称用在表达式中, 不能显式调用get访问器
class Program710_2 { private int theRealValue; public int MyValue { set { theRealValue = value; } get { return theRealValue; } } //使用属性 public void UseMyValue() { MyValue = 5;//设置属性 int z = MyValue;//读取属性 Console.WriteLine($"我的属性是: {z}"); } }
static void Main(string[] args) { Program710_2 program710_2 = new Program710_2(); program710_2.UseMyValue(); //5 program710_2.MyValue = 15; int Value = program710_2.MyValue; Console.WriteLine($"在main中我的属性是 :{Value}"); //15 }
(4)属性和关联字段
-
属性常常与字段关联, 一种常见的方式是在类中将字段声明为私有, 以封装该字段
-
并声明一个public属性来控制从类的外部对该字段的访问
-
和属性关联的字段常常被称为后备字段或后背存储
class Program710_4 { private int theRealValue = 10; //后备字段, 分配内存 public int MyValue { set { theRealValue = value; } get { return theRealValue; } } }
static void Main(string[] args) { Program710_4 program710_4 = new Program710_4(); Console.WriteLine($"类的属性值是: {program710_4.MyValue}"); program710_4.MyValue = 20; Console.WriteLine($"设置类的属性值为: {program710_4.MyValue}"); }
属性和关联字段的命名
-
第一种命名: 两个名称使用相同的内容, 但是字段小驼峰, 属性大驼峰
class Program710_4 { private int myValue = 10; //后备字段, 分配内存 public int MyValue { set { myValue = value; } get { return myValue; } } } -
第二种命名: 两个名称使用相同内容, 但是字段小驼峰并以下划线开始, 属性大驼峰
class Program710_4 { private int _myValue = 10; //后备字段, 分配内存 public int MyValue { set { _myValue = value; } get { return _myValue; } } }
(5)执行其他计算
属性访问器不限于对后备字段传入传出数据, 访问器可以进行任何计算, 唯一必须的行为是get访问器要返回一个属性类型的值
private int _myValue = 10; public int MyValue { //如果赋值大于100就设置属性为100否则设置属性为赋值 set { _myValue = value > 100 ? 100 : value; } get { return _myValue; } } }
Lamba表达式
class Progrom710_5 { private int _myValue = 10; public int MyValue { //如果赋值大于100就设置属性为100否则设置属性为赋值 set { _myValue = value > 100 ? 100 : value; } get => _myValue; } }
(6)只读和只写属性
想要不定义某个属性的某个访问器, 可以直接忽略该访问器的声明
-
只有get访问器的属性称为只读属性
-
能够将安全的将一个数据项从类或类的实例中传出, 而不必让调用者修改属性值
-
-
只有set访问器称为只写属性
-
没有实际用途, 如果想在赋值时触发一个副作用最好调用方法去修改
-
-
两个访问器至少有一个需要被定义, 否则报错
(7)属性与公有字段
属性比公有字段更好, 理由如下
-
属性是函数成员, 而不是数据成员, 允许你处理输入和输出, 而公有字段不行
-
属性可以只读或只写, 而字段不行
-
编译后的变量和编译后的属性语义不同
(8)只读属性例子
类RightTrangle表示一个三角形
-
他有2个公有字段, 分别表示两条直角边的长度, 这两个字段可以被写入和读取
-
第三条边由属性Hypotenuse表示, 他是一个只读属性, 其返回值基于另外两条边的长度, 没有存储在字段中, 相反他需要根据两条直角边的值计算正确的值
class RightTrangle { public double A; public double B; public double C { get { return Math.Sqrt((A * A) + (B * B)); } } }
(9)自动实现属性
因为属性经常被关联到后背字段, 所以提供了自动实现属性, 常简称为“ 自动属性 ”, 允许只声明属性而不声明后背字段, 编译器会为你创建隐藏的后备字段, 并自动挂载到getter、setter
-
不声明后备字段: 编译器根据属性的类型分配存储
-
不能提供访问器的方法体: 它必须被简单的声明为分号
-
get担当简单的内存读
-
set担当简单的写
-
-
但是因为无法访问自动属性的方法体, 调试代码困难
class Program710_9 { public int MyValue { set; get; } }
Program710_9 program710_9 = new Program710_9(); program710_9.MyValue = 10; int myValue = program710_9.MyValue; Console.WriteLine($"使用自动实现属性, 属性为: {myValue}");
(10)静态属性
属性可以声明为static, 静态属性的访问器和所有静态成员一样, 特点如下
-
不能访问类的实例成员, 但是能被实例成员访问
-
不管类是否有实例, 他们都是存在的
-
在类的内部, 可以仅使用名称来引用静态属性
-
在类的外部, 可以使用类名或using static结构引用静态属性
class Program710_10 { public static int MyValue { set; get; } //内部调用静态属性 public void PrintMyValue() { Console.WriteLine($"内部调用静态属性, 属性值: {MyValue}"); } }
static void Main(string[] args) { Program710_10 program710_10 = new Program710_10(); program710_10.PrintMyValue(); //传统方式外部访问静态属性 Program710_10.MyValue = 10; int staticValue = Program710_10.MyValue; Console.WriteLine($"在类的外部, 传统方法调用静态属性, 属性值为: {staticValue}"); //使用using static外部访问静态属性 MyValue = 20; int usingStaticValue = MyValue; Console.WriteLine($"在类的外部, 使用using static调用静态属性, 属性值为{usingStaticValue}"); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律