在C#中,属性(Property)是对字段的封装,通过get和set访问器可以控制字段的读取和赋值逻辑,既保证了数据的安全性,又维持了类似字段的访问体验。属性不需要直接暴露内部字段,而是可以通过访问器添加校验、日志等额外逻辑。

属性的基本定义方式
最基础的属性定义需要包含get和set访问器,get用于返回字段的值,set用于设置字段的值,其中set访问器自带一个隐式参数value表示传入的赋值。
// 定义私有字段存储数据
private string _name;
// 定义带get和set的属性
public string Name
{
get
{
return _name;
}
set
{
// 可以在set中添加赋值校验逻辑
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("姓名不能为空");
}
_name = value;
}
}
自动属性(Auto-Implemented Properties)
如果不需要在get和set中添加额外逻辑,C#提供了自动属性的语法,编译器会自动生成对应的私有字段,简化代码编写。
// 自动属性,编译器会自动生成隐藏的私有字段
public int Age { get; set; }
// 只读自动属性,只有get访问器,初始化后无法修改
public string Id { get; }
// 只写自动属性,只有set访问器,很少使用
public string Password { private get; set; }
不同访问权限的属性配置
get和set访问器可以单独设置访问修饰符,默认情况下访问器和属性的访问权限一致,也可以将set设为私有,实现只读对外的属性。
public class User
{
// 外部只能读取,内部可以赋值
public string UserName { get; private set; }
// 只有类内部可以读取和赋值
public int Score { private get; set; }
public void InitUser(string name)
{
UserName = name;
Score = 0;
}
}
属性的使用场景
属性适合用在需要控制字段访问逻辑的场景,比如字段赋值需要校验、字段读取需要计算、需要对外暴露只读数据等情况。以下是完整的示例类:
public class Product
{
private decimal _price;
// 带校验的价格属性
public decimal Price
{
get { return _price; }
set
{
if (value < 0)
{
throw new ArgumentException("价格不能为负数");
}
_price = value;
}
}
// 只读的折扣后价格属性,通过计算得到
public decimal DiscountPrice
{
get { return _price * 0.9m; }
}
// 自动属性
public string ProductName { get; set; }
}
class Program
{
static void Main(string[] args)
{
Product p = new Product();
p.ProductName = "笔记本";
p.Price = 5000;
Console.WriteLine($"商品名:{p.ProductName},原价:{p.Price},折扣价:{p.DiscountPrice}");
}
}
get和set的注意事项
- get访问器不应该有副作用,比如修改其他字段的值,避免造成逻辑混乱
- 如果属性只有get访问器,初始化后无法修改,适合表示不可变数据
- set访问器中的
value是上下文关键字,不需要额外定义,直接使用即可 - 属性可以作为方法参数传递,也可以用在LINQ查询中,使用方式和字段一致