C# 类(Class)(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

在 C# 开发中,类(Class) 是面向对象编程(OOP)的核心概念之一。它不仅是代码组织的基本单元,也是实现复用性、封装性和扩展性的关键工具。无论是构建简单的控制台应用,还是复杂的分布式系统,开发者都离不开对 C# 类(Class) 的理解和应用。本文将从基础到进阶,通过案例与代码示例,深入讲解 C# 类(Class) 的设计原理与实践技巧,帮助读者掌握这一重要概念。


类的定义与基本结构

什么是类?

类可以理解为一个“蓝图”或“模板”,用于描述某一类型对象的共同特征和行为。例如,一个 Person 类可以定义人类的属性(如姓名、年龄)和方法(如说话、行走)。通过这个模板,我们可以创建多个 Person 对象,每个对象都拥有类定义的属性和行为。

示例代码:定义一个简单的类

public class Person  
{  
    // 字段(Field):存储数据  
    private string name;  
    private int age;  

    // 方法(Method):定义行为  
    public void SayHello()  
    {  
        Console.WriteLine($"Hello, my name is {name}!");  
    }  
}  

类的成员类型

一个类通常包含以下成员:

  1. 字段(Field):用于存储数据,通常声明为 private 以确保封装性。
  2. 属性(Property):用于提供对字段的访问控制,例如通过 getset 方法。
  3. 方法(Method):定义类的行为,如计算、操作数据等。
  4. 构造函数(Constructor):用于初始化对象的状态。

表格对比:字段与属性的区别

(空一行后插入表格)
| 特性 | 字段(Field) | 属性(Property) |
|--------------|----------------------------|-------------------------------|
| 访问控制 | 通常直接暴露(如 public) | 可通过 get/set 限制访问 |
| 代码简洁性 | 更简单,直接赋值 | 需定义 getset 方法 |
| 功能扩展 | 无法直接添加逻辑 | 可在 get/set 中添加验证 |


类的实例化与对象

对象的创建

通过 new 关键字可以创建类的实例(对象)。例如:

Person person = new Person();  
person.name = "Alice"; // 直接访问字段(但需确保字段是 `public`)  
person.SayHello();     // 调用方法  

注意事项:字段的访问权限

如果字段声明为 private,则外部无法直接访问。此时需要通过属性或方法间接操作:

public class Person  
{  
    private string name;  

    // 通过属性提供安全的访问  
    public string Name  
    {  
        get { return name; }  
        set { name = value; }  
    }  
}  

// 使用属性  
Person person = new Person();  
person.Name = "Alice"; // 通过属性设置值  

类的访问修饰符

什么是访问修饰符?

访问修饰符决定了类、成员或方法的可见范围。C# 中常见的修饰符包括 publicprivateprotected 等。

示例:不同修饰符的效果

public class AccessExample  
{  
    private int privateField; // 仅当前类可访问  
    protected int protectedField; // 当前类及子类可访问  
    public int publicField; // 全局可访问  
}  

表格:修饰符的作用域对比

(空一行后插入表格)
| 修饰符 | 作用域 |
|----------|-----------------------------------------------------------------------|
| public | 可被任何其他代码访问。 |
| private| 仅限于声明该成员的类内部访问。 |
| protected| 可被同一类或其派生类访问。 |
| internal| 可被同一程序集(Assembly)内的代码访问。 |


继承:类的扩展与复用

继承的概念

继承允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码复用。例如,Student 类可以继承自 Person 类:

public class Student : Person  
{  
    public string StudentID { get; set; }  

    // 重写父类方法  
    public override void SayHello()  
    {  
        base.SayHello(); // 调用父类方法  
        Console.WriteLine($"My student ID is {StudentID}");  
    }  
}  

继承的注意事项

  • 基类与派生类:子类可以添加新成员,但无法移除继承的成员。
  • 构造函数:子类需显式调用父类的构造函数(通过 base())。

多态:灵活的行为定义

多态的实现方式

多态允许不同类的对象通过统一接口调用,但表现出不同行为。C# 中通过 方法重写(Override)接口实现 实现多态:

示例:通过虚方法实现多态

public class Animal  
{  
    public virtual void MakeSound()  
    {  
        Console.WriteLine("Animal makes a sound");  
    }  
}  

public class Dog : Animal  
{  
    public override void MakeSound()  
    {  
        Console.WriteLine("Dog barks!");  
    }  
}  

// 使用  
Animal animal = new Dog();  
animal.MakeSound(); // 输出 "Dog barks!"  

关键点:virtualoverride

  • virtual:在父类方法中声明,允许子类重写。
  • override:在子类中重写父类的 virtual 方法。

封装:隐藏复杂性与保护数据

封装的核心思想

封装通过将数据和行为捆绑,并限制直接访问内部状态,从而提升代码的安全性和可维护性。例如:

public class BankAccount  
{  
    private decimal balance; // 私有字段,外部无法直接修改  

    public decimal Balance  
    {  
        get { return balance; }  
        private set // 仅允许类内部设置值  
        {  
            if (value < 0) throw new ArgumentException("Balance cannot be negative");  
            balance = value;  
        }  
    }  

    public void Deposit(decimal amount)  
    {  
        Balance += amount; // 通过属性验证  
    }  
}  

封装的优势

  1. 数据验证:确保数据符合业务规则(如金额不能为负)。
  2. 接口稳定:即使内部实现变化,外部调用方式不变。

高级特性:抽象类与接口

抽象类(Abstract Class)

抽象类不能被实例化,主要用于定义通用功能和强制子类实现特定方法:

public abstract class Shape  
{  
    public abstract double CalculateArea(); // 抽象方法,无实现  

    // 具体方法  
    public void PrintArea()  
    {  
        Console.WriteLine($"Area: {CalculateArea()}");  
    }  
}  

public class Circle : Shape  
{  
    public double Radius { get; set; }  

    public override double CalculateArea()  
    {  
        return Math.PI * Radius * Radius;  
    }  
}  

接口(Interface)

接口定义了一组方法“契约”,类可以实现多个接口,实现多重继承:

public interface IAnimal  
{  
    void Move();  
}  

public interface IEat  
{  
    void Eat();  
}  

public class Dog : IAnimal, IEat  
{  
    public void Move() => Console.WriteLine("Dog is running");  
    public void Eat() => Console.WriteLine("Dog is eating");  
}  

实际案例:学生管理系统

需求:管理学生信息

我们需要一个系统,记录学生的姓名、年龄、成绩,并支持计算平均分。

步骤 1:定义 Student

public class Student  
{  
    public string Name { get; set; }  
    public int Age { get; set; }  
    public List<int> Scores { get; set; } = new List<int>();  

    public double CalculateAverage()  
    {  
        return Scores.Average();  
    }  
}  

步骤 2:创建 StudentManager

public class StudentManager  
{  
    private List<Student> students = new List<Student>();  

    public void AddStudent(Student student)  
    {  
        students.Add(student);  
    }  

    public void PrintAllAverages()  
    {  
        foreach (var student in students)  
        {  
            Console.WriteLine($"{student.Name}'s average: {student.CalculateAverage()}");  
        }  
    }  
}  

步骤 3:使用案例

var manager = new StudentManager();  
var alice = new Student { Name = "Alice", Age = 20 };  
alice.Scores.Add(90); alice.Scores.Add(85);  
manager.AddStudent(alice);  

manager.PrintAllAverages(); // 输出 Alice 的平均分  

常见问题与最佳实践

问题 1:为什么类成员需要封装?

直接暴露字段可能导致数据被意外修改(如 student.Age = -5)。通过属性,可以添加验证逻辑,确保数据合法性。

问题 2:抽象类与接口的区别?

  • 抽象类:适合定义共享实现和强制继承结构。
  • 接口:适合定义行为“契约”,支持多继承。

最佳实践

  1. 单一职责原则:一个类只负责一个功能模块。
  2. 避免过度继承:优先使用组合而非继承扩展功能。
  3. 合理使用 private:默认将字段设为 private,通过属性提供访问。

结论

C# 类(Class) 是构建复杂应用的基础,它通过封装、继承和多态等特性,帮助开发者编写高效、可维护的代码。无论是设计简单的数据结构,还是构建庞大的系统,理解类的定义、成员管理、继承关系以及高级特性(如抽象类和接口)都是关键。通过实际案例的演练,读者可以进一步掌握如何将理论应用于实践,最终实现灵活且健壮的 C# 应用程序。

希望本文能为编程初学者和中级开发者提供清晰的指导,并激发对面向对象编程更深层次的兴趣。

最新发布