属性与方法
这是什么:属性(property)——长得像字段、实则是一对 get/set 方法的"带门卫的字段"。
为什么用:上一章用 public string Name 存名字——能用,但有个隐患:外面可以随便 d.Age = -5,哪有负几岁的狗?属性就是给数据装的门卫,坏数据进不来。
如何用:本章先给 Dog 加一个自动属性,再把 Age 改成带校验的完整属性,试试负数还能不能塞进去。
属性:带门卫的字段
属性长得像字段,其实是一对方法:get 管"读",set 管"写",数据进出都要过门卫。
Dog d = new Dog { Name = "旺财" }; // 对象初始化器:一行喂多个属性
d.Age = -5; // 想搞破坏?没门
Console.WriteLine($"{d.Name} 今年 {d.Age} 岁");
class Dog
{
public string Name { get; set; } // 自动属性:不需要检查,一行搞定
private int age; // 真正存数据的字段,private 锁起来
public int Age // 属性:读写都过门卫
{
get { return age; }
set
{
if (value < 0) value = 0; // value 代表"别人塞进来的值"
age = value;
}
}
}
运行输出:
旺财 今年 0 岁
-5 被门卫拦下改成 0。这就是属性的价值:数据不是想塞就塞,得先过检查。
| 写法 | 什么时候用 |
|---|---|
{ get; set; } 自动属性 |
读写不需要检查(大多数情况) |
完整 get / set |
读写要加校验、联动等规则 |
只有 get; |
只许读不许改,比如编号 |
和 Java 对比:少写一半
Java 里要手写一对 getter/setter,用的时候也是调方法:
d.setName("旺财"); // Java:调方法
System.out.println(d.getName());
C# 直接用属性,像访问字段一样自然:
d.Name = "旺财"; // 看着是赋值,实际走 set
Console.WriteLine(d.Name); // 看着是读字段,实际走 get
写起来短,改起来灵活:哪天要加校验,只改属性内部,用它的一百行代码一个字都不用动。
方法与表达式体成员
方法还是老写法,但只有一行时可以缩成"表达式体":用 => 直接给结果。
class Dog
{
public string Name { get; set; }
public int Age { get; set; }
public void Bark() // 普通写法
{
Console.WriteLine($"{Name}:汪汪!");
}
public void Wag() => Console.WriteLine($"{Name} 疯狂摇尾巴"); // 表达式体
public string Info => $"{Name}({Age}岁)"; // 只读属性也能这么写
}
Wag() 和 Info 都是一行,=> 后面直接就是内容。以后在别人代码里见到 => 别慌——展开大括号就是你熟悉的写法。
记忆口诀
字段裸奔要出事,属性把门 get set 拦;一行方法打个箭头,代码瘦身看得见。
动手改
- 给
Age的set再加一条规则:超过 30 也不行,按 30 算 - 写一个只读属性
Description,返回"XX 是一只 X 岁的狗"并打印 - 把
Bark()改成表达式体写法,运行验证输出没变
下一章:继承与多态,让代码代代相传 🐸