欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 幼教 > C#核心学习(二)面向对象——封装(1)成员变量与成员方法

C#核心学习(二)面向对象——封装(1)成员变量与成员方法

2025/9/27 2:56:53 来源:https://blog.csdn.net/m0_74212916/article/details/146718360  浏览:    关键词:C#核心学习(二)面向对象——封装(1)成员变量与成员方法

        在上一篇文章中,我们初始了类以及对象。今天我们继续学习面向对象中的封装特性中的成员变量及成员方法。

一、什么是封装?

        官方解释:封装是面向对象编程的基石,通过绑定数据与操作控制访问权限,实现数据保护和逻辑隔离。
        程序员翻译

“把你的代码想象成一座城堡:

  • 成员变量是藏在金库里的黄金
  • 成员方法是城堡的守卫和交易窗口
  • 访问修饰符是金库的密码锁”

示例:

public class Bank {private decimal _goldReserves; // 黄金藏在金库(private)public void Withdraw(decimal amount) { // 交易窗口(public方法)if (amount <= _goldReserves) _goldReserves -= amount;}
}

        下面的示例是一个类里面我们可以申明写什么东西,可以申明各式各样的类型的变量,就和前面我们在函数中申明的变量一样,只不过这个类里面申明的变量的使用范围和访问修饰符有关。 

    class Person{//特征-成员变量//姓名public string name;//年龄public int age;//性别public E_SexType sex;//朋友public Person[] boyFriend;//如果在类中申明一个和自己同名的成员变量 但不能对他实例化 否则内存爆炸}

二、为什么需要封装?

1. ​**防止“魔法数值”攻击

直接暴露字段等于在代码里写“欢迎来搞破坏”:

public class User {public int Age = 25; // 公共字段?危险!
}// 魔鬼操作:
User user = new User();
user.Age = -30; // 年龄-30岁?时间旅行者?

封装后的救赎

private int _age;
public int Age {set => _age = value >= 0 ? value : throw new Exception("年龄不能为负!");
}

        注意:这里的Age是一个属性,我们后面会详细的讲述,你在这里可以直接把他理解为一个方法即可。

2. ​代码维护:换引擎不用换车

        假设你有一个Car类:

  • 直接暴露Engine字段:升级电动引擎需修改所有调用代码
  • 封装后:只需修改内部实现,用户仍调用StartEngine()

工程师哲学

用户不需要知道发动机是烧油还是用电,踩油门能跑就行!”

三、访问修饰符——代码的“权限卡” 

public 公共的 自己内部和外部都能访问使用
private 私有的 自己的内部才能访问使用 不写 默认private
protected 保护的 自己和自己的子类 才能访问和使用

internal是C#中的访问修饰符,表示成员或类型仅在当前程序集(Assembly)内可见。

修饰符权限说明适用场景
private仅限当前工牌员工访问敏感数据(如密码、密钥)
public访客也能用的公共电梯工具方法(如CalculateSum()
protected家族企业继承权基类共享给派生类的数据
internal公司内部机密文件同一程序集的工具类

        注意:internal的作用

核心用途
  1. ​程序集内部共享:
    • 适用于在同一个项目(如一个DLL或EXE)中共享类、方法或字段,但对其他项目不可见。
  2. ​替代public的受限场景:
    • 当需要对外隐藏实现细节,但允许同一程序集内协作时使用。

示例场景

        假设你有一个类库项目 MyUtilities.dll(类库是什么我们后面再说,这里只是举例说明internal的作用),其中包含

// 仅在MyUtilities.dll内可见
internal class InternalLogger {public static void Log(string message) {Console.WriteLine($"[LOG] {message}");}
}// 同一程序集中的其他类可以调用
public class DataProcessor {public void Process() {InternalLogger.Log("Processing started"); // 合法}
}

        外部项目引用MyUtilities.dll时:无法访问InternalLogger类。

四、成员变量

 基本规则
1.申明在类语块中
2.用来描述对象的特征
3.可以是任意变量类型
4.数量不做限制
5.是否赋值根据需求来定

        你可以把他理解为就是申明一个变量,之前我们都是在一个函数中申明,现在跑到一个类里面进行申明和使用了。 

五、成员方法 

基本概念
成员方法(函数)用来表现对象的行为
1.申明在类语句块中
2.用来描述对象的行为的
3.规则和函数申明规则相同
4.收到访问修饰符规则限制
5.返回值参数不受限制
6.方法数量不受限制

注意
1.成员方法不要加static关键字
2.成员方法 必须实例化出对象 再通过对象来使用 相当于是该对象执行了某个行为
3.成员方法 收到访问修饰符的影响

        就是待在类里面的函数,之前我们都是在系统直接给我们提供好的类里面进行编写代码,现在我们要将要刻画的对象抽象成一个类来自己进行描述。 

下面是一个完整的示例:

using System;// 定义学生状态枚举
public enum StudentStatus
{Active,     // 在读状态Graduated,  // 已毕业Suspended   // 休学中
}// 定义课程成绩结构体
public struct GradeRecord
{public string CourseName; // 课程名称public float Score;       // 分数值(0-100)public bool IsPassed;     // 是否及格(>=60为true)
}public class Student
{/* ================== 成员变量 ================== */private int _id;                     // 学生唯一标识(学号)private float _gpa;                  // 平均绩点(0-4.0)private bool _isScholarship;         // 是否获得奖学金private StudentStatus _status;       // 学生当前状态private GradeRecord[] _grades;       // 所有课程成绩记录private Student[] _friends;          // 好友列表(学生对象数组)private static int _totalStudents;    // 静态变量:学生总数统计/* ================== 属性封装 ================== */// 学号属性(只读,初始化后不可修改)public int Id{get => _id;// set私有化,初始化时验证学号有效性private set => _id = value > 0 ? value : throw new ArgumentException("学号必须为正整数");}// GPA属性(只读,通过成绩自动计算)public float GPA{get => _gpa;// 私有set确保只能通过AddGrade方法修改private set => _gpa = Math.Clamp(value, 0f, 4.0f); // 限制在0-4.0范围}// 奖学金状态(可读写)public bool IsScholarship{get => _isScholarship;set => _isScholarship = value; // 允许外部直接修改}// 学生状态(可读写)public StudentStatus Status{get => _status;set => _status = value; // 允许外部修改状态}// 成绩记录数组(完整读写控制)public GradeRecord[] Grades{get => _grades;// 设置时进行空值检查set => _grades = value ?? throw new ArgumentNullException("成绩记录不可为空");}// 好友列表(安全访问控制)public Student[] Friends{get{// 返回数组拷贝,防止外部直接修改内部数据Student[] copy = new Student[_friends.Length];Array.Copy(_friends, copy, _friends.Length);return copy;}}/* ================== 构造方法 ================== */public Student(int id, float gpa, StudentStatus status){Id = id;GPA = gpa;          // 初始GPA由外部传入Status = status;_grades = new GradeRecord[0];  // 初始化空成绩数组_friends = new Student[0];     // 初始化空好友数组_totalStudents++;              // 静态计数器自增}/* ================== 成员方法 ================== */// 添加课程成绩public void AddGrade(string courseName, float score){// 数据有效性验证if (string.IsNullOrWhiteSpace(courseName))throw new ArgumentException("课程名不能为空");if (score < 0 || score > 100)throw new ArgumentException("分数必须在0-100之间");// 创建新的成绩记录var newGrade = new GradeRecord{CourseName = courseName,Score = score,IsPassed = score >= 60 // 自动计算是否及格};// 扩展数组并添加新记录Array.Resize(ref _grades, _grades.Length + 1);_grades[_grades.Length - 1] = newGrade;// 更新GPA(根据实际业务逻辑可能需要更复杂计算)UpdateGPA();}// 添加好友public void AddFriend(Student friend){// 防御性编程if (friend == null)throw new ArgumentNullException(nameof(friend), "好友不能为空");if (friend == this)throw new ArgumentException("不能添加自己为好友", nameof(friend));if (Array.Exists(_friends, f => f.Id == friend.Id))return; // 避免重复添加// 动态扩容数组Array.Resize(ref _friends, _friends.Length + 1);_friends[_friends.Length - 1] = friend;}// 移除好友public bool RemoveFriend(int friendId){// 查找好友索引int index = Array.FindIndex(_friends, f => f.Id == friendId);if (index == -1) return false;// 数组元素前移for (int i = index; i < _friends.Length - 1; i++){_friends[i] = _friends[i + 1];}// 动态缩容Array.Resize(ref _friends, _friends.Length - 1);return true;}/* ================== 私有方法 ================== */// GPA计算逻辑(可根据实际需求修改)private void UpdateGPA(){if (_grades.Length == 0){GPA = 0;return;}float totalScore = 0;foreach (var grade in _grades){totalScore += grade.Score;}// 简单转换为4分制(实际可能需要学分加权)GPA = totalScore / _grades.Length / 25f;}/* ================== 信息输出 ================== */public void PrintInfo(){Console.WriteLine($"学号: {Id}");Console.WriteLine($"GPA: {GPA:F2}");Console.WriteLine($"奖学金状态: {(IsScholarship ? "是" : "否")}");Console.WriteLine($"在读状态: {Status}");Console.WriteLine("成绩记录:");foreach (var grade in _grades){Console.WriteLine($"  {grade.CourseName.PadRight(15)}: {grade.Score,5:F1} ({(grade.IsPassed ? "✓" : "✕")})");}Console.WriteLine("好友列表:");foreach (var friend in _friends){Console.WriteLine($"  ▶ 学号{friend.Id} | GPA: {friend.GPA:F2}");}Console.WriteLine(new string('=', 40));}/* ================== 静态方法 ================== */public static int GetTotalStudents() => _totalStudents;
}class Program
{static void Main(){// 初始化学生对象Student alice = new Student(1001, 3.5f, StudentStatus.Active);Student bob = new Student(1002, 2.8f, StudentStatus.Active);Student charlie = new Student(1003, 3.9f, StudentStatus.Active);// 建立好友关系alice.AddFriend(bob);alice.AddFriend(charlie);bob.AddFriend(alice);// 添加课程成绩alice.AddGrade("面向对象编程", 88.5f);alice.AddGrade("数据结构", 92.0f);bob.AddGrade("C#基础", 78.5f);charlie.AddGrade("算法设计", 95.0f);// 修改学生状态alice.IsScholarship = true;bob.Status = StudentStatus.Suspended;// 输出信息alice.PrintInfo();bob.PrintInfo();charlie.PrintInfo();// 移除好友演示alice.RemoveFriend(1002);Console.WriteLine("Alice移除了Bob后的好友列表:");alice.PrintInfo();// 统计学生总数Console.WriteLine($"全校学生总数: {Student.GetTotalStudents()}");}
}

关键设计注释说明

 ​1、好友列表安全访问: 

public Student[] Friends {get {Student[] copy = new Student[_friends.Length];Array.Copy(_friends, copy, _friends.Length);return copy;}
}
  • 防御性拷贝:返回数组副本防止外部代码直接修改内部数据
  • 封装原则:保护对象内部状态不被意外修改

2、动态数组操作

Array.Resize(ref _friends, _friends.Length + 1);
_friends[_friends.Length - 1] = friend;
  • 灵活扩容:每次添加自动调整数组大小
  • 性能说明:实际开发建议使用List<T>,此处用数组演示底层原理

3、 ​数据验证机制

if (friend == null)throw new ArgumentNullException(nameof(friend), "好友不能为空");
if (friend == this)throw new ArgumentException("不能添加自己为好友");
  • 防御性编程:防止无效数据进入系统
  • 异常处理:明确错误原因,提高代码健壮性

4、 状态关联更新

private void UpdateGPA() {// 每次添加成绩后自动更新GPA
}
  • 数据一致性:确保GPA始终与成绩记录同步
  • 业务逻辑隔离:更新逻辑封装在私有方法中

总结:

特性成员变量(字段)成员方法
作用存储对象状态定义对象行为
访问控制通常private,通过属性暴露可设为publicprivate
典型操作直接赋值或读取通过参数传递数据,执行逻辑

    版权声明:

    本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

    我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

    热搜词