CodeGym /课程 /C# SELF /C#中的属性(Properties)

C#中的属性(Properties)

C# SELF
第 17 级, 课程 1
可用

1. 入门

咱们先来聊聊直接用字段会遇到啥问题。如果你把字段声明成public,那它就能被程序里任何地方直接改:

public class Dog
{
    public string Name;
}

Dog dog = new Dog();
dog.Name = ""; // O_o ... 这就像“狗的名字 = 空字符串”!

用户可以给Name字段赋各种离谱的值,比如空字符串、超长名字,甚至null。这就像你让别人组装你的新IKEA柜子,还把整个木工厂都交给他随便折腾。

提醒下,封装就是对象自己管好自己的数据。我们不会让每个人都能随便动内部数据,而是给出专门的“门”——属性(Properties),通过它们访问字段,还能加校验、日志、修改或者别的操作。

2. 定义和语法

属性是类里的特殊成员,看起来像字段,其实底层是两个特殊方法:getter(获取值)和setter(设置值)。用属性你可以:

  • 允许(或禁止)读/写数据;
  • 访问数据时加校验或逻辑;
  • 隐藏内部字段,甚至把值存别的地方。

属性声明和字段很像,只是多了大括号和get、set关键字。


[访问修饰符] 类型 属性名
{
    get { ... }
    set { ... }
}
属性声明模板

比如我们的Dog类:

public class Dog
{
    private string _name; // 内部字段(private!)

    public string Name
    {
        get { return _name; }  // “getter”:获取名字
        set { _name = value; } // “setter”:设置名字
    }
}

注意:下划线通常用在私有字段(_name)。这是C#的风格标准。

3. 属性的工作机制

属性就像“守门员”,站在对象内部数据和外部世界之间。举个例子:

Dog dog = new Dog();
dog.Name = "小花";
Console.WriteLine(dog.Name);

解释下:

  • 当程序执行到dog.Name = "小花";时,其实是调用了属性的set方法,你可以在里面加各种校验(比如名字不能是空的)。
  • 执行Console.WriteLine(dog.Name);时,会调用get方法,返回当前值,或者动态算一个值。

看起来像普通字段,其实一切都在你掌控中!

4. 为什么属性是“最佳实践”

大多数时候我们不会让对象的内部字段直接暴露。哪怕现在觉得不需要校验,习惯用属性包一层,等以后规则变了就超方便。

赋值时“校验”示例:


public class Dog
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentException("狗的名字不能为空!");
            }
            _name = value;
        }
    }
}

现在这样:

dog.Name = ""; // 会抛异常!

……保护了我们的对象不被赋奇怪的值。

5. 属性:只读、只写和普通属性

有时候你只想让别人看值(比如狗的出生年份,不能改),或者只让设置(很少见,但有时候你想搞点神秘操作)。

  • 只读:只写get,不写set。
  • 只写:只写set,不写get。

例子:

public class Dog
{
    private int _birthYear = 2018;

    // 只读
    public int BirthYear
    {
        get { return _birthYear; }
    }

    // 只写(极少用)
    public string Secret
    {
        set { /* 这里处理value */ }
    }
}

6. 属性 vs 字段

字段 属性
语法
public string Name;
public string Name { get; set; }
访问 直接 通过get/set
校验 没有 可以在set/get里加
可扩展性 没有 随时能改
IDE集成 显示为字段 显示为属性(对框架很重要)

图解:属性的工作流程

sequenceDiagram
participant User as 对象的用户
participant Dog as Dog对象
participant Field as 私有字段 _name

User->>Dog: dog.Name = "小黄"
Dog->>Dog: set Name("小黄")
Dog->>Field: _name = "小黄"

User->>Dog: print(dog.Name)
Dog->>Dog: get Name()
Dog->>Field: 读取 _name
Dog->>User: 返回 "小黄"

7. 常见错误和细节

来看看这里会踩哪些坑。

常见错误——把字段和属性搞混,不小心把私有数据暴露出去了:

public string name; // 这是字段!到处都能看到,危险!

正确姿势:

private string _name;
public string Name
{
    get { return _name; }
    set { _name = value; }
}

静态属性也有,用来存所有对象共享的值。但要小心用。

有趣:如果属性只有get,没有构造函数,那它根本改不了——这叫不可变属性(immutable property),在现代设计里很常见(我们后面讲record和数据不可变性会详细聊)。

2
任务
C# SELF, 第 17 级, 课程 1
已锁定
声明带有get和set访问器的属性
声明带有get和set访问器的属性
2
任务
C# SELF, 第 17 级, 课程 1
已锁定
带有输入校验的属性
带有输入校验的属性
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION