CodeGym /课程 /C# SELF /封装和访问修饰符

封装和访问修饰符

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

1. 入门

想象一下你在设计一辆现代汽车。里面有几百个复杂零件、敏感的电子设备、各种精细的设置。很明显,没人应该随便就能摸到发动机控制单元然后开始拧螺丝。如果谁都能乱动,车可能就会变得很奇怪,到时候你还得检查到底是谁把啥给弄坏了。

编程也是一样的。当你写一个类的时候,肯定想保护它的内部——不让别人随便改重要的数据,或者乱动那些外部根本不该知道的方法。这就是封装的本质——面向对象编程三大核心原则之一。

封装让你能把实现细节藏起来,明确规定哪些东西能“暴露”给外部,哪些必须留在内部。就像你只让用户打开手套箱,但把引擎盖锁得死死的。类自己决定哪些数据可以给外部代码看,哪些要保密。这样代码就更靠谱、更有逻辑,也更容易维护。

严格点说,封装——就是把数据(字段)和跟它相关的行为(方法)合成一个整体,同时限制外部直接访问对象内部组件的方式。

2. 访问修饰符:守护自己的地盘

在C#(还有其他OOP语言)里,封装是靠访问修饰符实现的。这些“标签”决定了类的哪些成员(字段、方法、属性等等)能被外部访问,哪些只能内部用。

我们之前其实已经见过它们了,不过还是来回顾一下,并且补充下常见的修饰符:

修饰符 可访问范围...
public
所有人!项目里的任何代码(如果是库,外部也能访问)
private
只有这个类内部能访问
protected
这个类和它所有的子类都能访问
internal
只在当前程序集(项目)里能访问
protected internal
要么在当前程序集,要么在子类里能访问
private protected
只有当前程序集里的子类能访问

这节课我们主要关注最常用的:public、private,顺带提一下protected,别让脑子太累。

区分内部和外部

来写个Dog类:


public class Dog
{
    public string Name;
    public int Age;

    public void Bark()
    {
        Console.WriteLine($"{Name} 说: 汪!");
    }
}

这里所有字段和方法都是public。也就是说,任何人都能改狗的名字或者年龄:

Dog rex = new Dog("雷克斯", 5);
rex.Name = "小花"; // 突然换了个身份!
rex.Age = -999;     // 年龄出大问题了

其实Name和Age这俩字段挺重要的,肯定不想让谁都能乱改。

这样写不太行

如果所有字段都public,就很容易破坏类的逻辑:外部随便一改,对象就不靠谱了。比如给狗设个负年龄,或者名字写成"%$#!??"。

3. 隐藏字段:用private

一般来说,类的字段都私有(用private修饰)。这样只有类内部才能改它们,外部根本动不了。


public class Dog
{
    private string name;
    private int age;

    public void Bark()
    {
        Console.WriteLine($"{name} 说: 汪!");
    }
}

现在如果外部想直接访问字段:

Dog rex = new Dog("雷克斯", 5);
rex.name = "小花";  // 编译错误

编译器会直接说:“没权限!”

为啥要这么严格?灵活性去哪了?

所有的“灵活性”其实是靠专门的方法或者属性(下节课会详细讲)来实现的,这样你可以按规则控制数据的访问和修改。

4. 封装实战:加点控制

比如说,我们想让狗的年龄不能设成负数:


public class Dog
{
    private string name;
    private int age;

    public Dog(string name, int age)
    {
        this.name = name;
        if (age >= 0)
            this.age = age;
        else
            this.age = 0; // 不让设“奇怪”的年龄
    }

    public void Bark()
    {
        Console.WriteLine($"{name} 说: 汪!");
    }

    // 安全修改年龄的方法
    public void SetAge(int newAge)
    {
        if (newAge >= 0)
            age = newAge;
        // 也可以加个else:提示值不对
    }
}

现在外部谁也不能直接搞坏字段了。要改年龄只能用专门的方法,而且会先检查一遍。

5. 字段 vs 访问方法(getter/setter)

这种做法——把字段设成private,然后提供方法来操作——就叫数据封装(data encapsulation)。想读字段值就写getter方法,想改就写setter方法。


public class Dog
{
    private string name;

    public Dog(string name)
    {
        this.name = name;
    }

    public string GetName()
    {
        return name;
    }

    public void SetName(string newName)
    {
        // 这里可以加名字合法性检查
        name = newName;
    }
}

不过! 自从C#有了属性(properties),这种方法就很少用了——属性让代码更简洁更好用(下节课会详细讲)。

6. 方法和类的访问修饰符

字段不是全部!访问修饰符也能用在方法(类成员函数)甚至类本身上。

只在类内部用的方法(比如内部逻辑的辅助函数),一般都设成private。

公开方法——就是类的接口(别和interface关键字搞混),也就是用户能用的那些东西。

7. 封装常见错误

错误1:啥都设成public。
觉得越多能访问越方便,其实这样会让外部能乱改类的内部,结果代码变得脆弱又难预测,尤其是大项目里。

错误2:改了访问修饰符导致外部代码崩了。
重构的时候不小心改了方法或字段的修饰符,结果其他用到它们的代码突然编译不过或者行为不对。尤其是公开API时更要小心。

错误3:把局部变量和类字段搞混。
有时候开发者忘了方法里声明的变量只在这个方法里活着,而类字段在所有方法里都能用。如果名字还一样就更容易出错。

错误4:忽视private和protected。
很多人怕用受限访问,担心以后用不到。其实封装就是要把多余的东西藏起来,只暴露真正需要的部分。

2
任务
C# SELF, 第 17 级, 课程 0
已锁定
通过方法实现访问控制
通过方法实现访问控制
2
任务
C# SELF, 第 17 级, 课程 0
已锁定
使用封装和数据有效性检查
使用封装和数据有效性检查
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION