C#彻底搞懂属性(Property)与字段(Field)

一、字段(Field)

字段是类或结构中直接声明的变量。它的唯一使命,就是作为对象状态的一部分,存储数据。

1. 字段的声明

csharp 复制代码
public class Student
{
    // 这就是两个字段
    public string Name; // 学生姓名
    public int Age;     // 学生年龄
}

2. 访问修饰符 -- Public

csharp 复制代码
Student stu = new Student();
stu.Name = "张三";
stu.Age = -10; // 灾难!年龄怎么可能是负数?

Console.WriteLine($"{stu.Name}的年龄是 {stu.Age}岁。");
// 输出: 张三的年龄是 -10岁。
  • 使用Public可以在任何时候,任何地方直接访问,并且修改,这会存在某些隐患

3. 访问修饰符 -- Private

  • Getter/Setter方法模式
csharp 复制代码
public class Student
{
    // 将字段设为private,外界无法直接访问
    private string _name;
    private int _age;

    // 为了让外界能设置和获取值,我们提供一对公开的方法
    public string GetName()
    {
        return _name;
    }

    public void SetName(string name)
    {
        // 可以在这里加入验证逻辑
        if (string.IsNullOrWhiteSpace(name))
        {
            Console.WriteLine("姓名不能为空!");
            return;
        }
        _name = name;
    }

    public int GetAge()
    {
        return _age;
    }

    public void SetAge(int age)
    {
        // 验证逻辑!
        if (age < 0 || age > 150)
        {
            Console.WriteLine("年龄不合法!");
            return;
        }
        _age = age;
    }
}

// === 使用 ===
Student stu = new Student();
stu.SetName("李四");
stu.SetAge(-10); // 输出: 年龄不合法!
stu.SetAge(25);

Console.WriteLine($"{stu.GetName()}的年龄是 {stu.GetAge()}岁。");

二、属性(Property)

属性是字段的自然演进。它为私有字段提供了一个公开的、受控的访问层,但在语法上,它看起来就像一个公有字段。它巧妙地结合了方法的灵活性和字段的简洁性。

1. 属性的完整声明

一个完整的属性包含一个私有的字段 和一对get/set访问器(Accessor)

csharp 复制代码
public class Student
{
    // 1. 私有字段,用于实际存储数据
    private int _age;

    // 2. 公开属性,作为外界访问的入口
    public int Age
    {
        // 3. get访问器:当读取属性时执行
        get
        {
            // 可以加入逻辑,比如权限检查
            return _age;
        }

        // 4. set访问器:当给属性赋值时执行
        set
        {
            // 'value'是一个上下文关键字,代表赋过来的值
            if (value < 0 || value > 150)
            {
                // 可以抛出异常,这是更推荐的做法
                throw new ArgumentOutOfRangeException(nameof(Age), "年龄必须在0到150之间。");
            }
            _age = value;
        }
    }
}

// === 使用属性 ===
Student stu = new Student();
try
{
    stu.Age = 25; // 调用set访问器,value为25
    Console.WriteLine(stu.Age); // 调用get访问器

    stu.Age = -10; // 调用set访问器,value为-10,抛出异常
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

三、属性的进阶 - 语法糖

C#语言在不断发展,属性的写法也越来越简洁。

1. 自动实现属性(Auto-Implemented Properties)

在很多情况下,我们的属性不需要任何特殊的验证逻辑,只是简单地存取一个值。为这种情况手写字段和get/set代码块显得很冗余。于是,C# 引入了自动属性。

csharp 复制代码
public class Product
{
    // 这就是自动属性
    // 编译器会自动在幕后创建一个私有的、匿名的字段
    public string Name { get; set; }
    public decimal Price { get; set; }
}

// === 使用 ===
Product phone = new Product();
phone.Name = "Phone X"; // 背后调用了自动生成的set
phone.Price = 999.99m;

这是我们日常开发中最常用的形式。简洁、高效。只有当你需要添加自定义逻辑时,才需要退回到手动实现字段的方式。

2. 控制可访问性

我们可以为getset访问器设置不同的访问级别。

csharp 复制代码
public class Order
{
    // Id只能在类的内部被设置(比如在构造函数中)
    // 但可以在任何地方被读取
    public int Id { get; private set; }

    public DateTime OrderDate { get; } // 只有get,这是一个只读属性

    public Order(int id)
    {
        this.Id = id; // 在内部设置是合法的
        this.OrderDate = DateTime.UtcNow; // 只读属性只能在构造函数或声明时赋值
    }
}

3. 表达式主体属性

对于一些只读的、由其他数据计算得出的属性,C# 提供了更简洁的写法。

csharp 复制代码
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    // 这个只读属性的值是计算出来的
    public string FullName => $"{FirstName} {LastName}";
}

四、C#中的特殊属性

1. init访问器

init 访问器让属性拥有了特殊的"只写一次"能力。它允许属性在对象初始化器中被赋值,但在那之后就变成只读。

csharp 复制代码
public class Book
{
    public string Isbn { get; init; } // 注意是init
    public string Title { get; init; }
}

// === 使用 ===
var book = new Book
{
    Isbn = "978-0321765723", // 合法!在对象初始化器中赋值
    Title = "The C# Programming Language"
};

// book.Title = "New Title"; // 编译错误!初始化完成后,不能再修改

2. required修饰符

创建对象时必须为某个属性赋值。

csharp 复制代码
public class User
{
    public int Id { get; set; }
    public required string Username { get; set; } // 必须在创建时提供值
    public string? Email { get; set; } // 可选
}

// === 使用 ===
// var user1 = new User(); // 编译错误!Username是required的,但没有被赋值。
var user2 = new User { Username = "alice" }; // 正确

结语

点个赞,关注我获取更多实用 C# 技术干货!如果觉得有用,记得收藏本文!

相关推荐
崔庆才丨静觅18 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606119 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了19 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅19 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅20 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
懒人咖20 小时前
缺料分析时携带用料清单的二开字段
c#·金蝶云星空
崔庆才丨静觅20 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment20 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅20 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊20 小时前
jwt介绍
前端