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}");
}