更复杂的结构 - 类与对象

专栏导航

← 上一篇:组织代码 - 方法/函数

← 第一篇:

更复杂的结构 - 类与对象

什么是面向对象编程(OOP)?

传统编程 vs 面向对象编程

传统编程(面向过程):

  • 关注"怎么做"(步骤、流程)
  • 数据和行为分离
  • 适合简单任务

面向对象编程(OOP):

  • 关注"谁来做"(对象)
  • 数据和行为封装在一起
  • 适合复杂系统

现实生活中的例子

想象你要描述一只猫:

面向过程:

复制代码
猫的颜色 = 白色
猫的体重 = 5kg
猫吃鱼
猫睡觉

面向对象:

复制代码
猫
├── 属性(特征)
│   ├── 颜色:白色
│   ├── 体重:5kg
│   └── 年龄:2岁
└── 方法(行为)
    ├── 吃鱼()
    ├── 睡觉()
    └── 叫()

面向对象的核心思想

将现实世界中的事物抽象为对象 ,每个对象都有自己的属性 (特征)和方法(行为)。

为什么面向对象重要?

更接近现实 :代码结构和现实世界相似,易于理解

代码复用 :通过继承实现代码复用

易于维护 :修改一个类不影响其他部分

封装性好 :隐藏内部实现细节

可扩展性强:方便添加新功能

类和对象

类(Class)

类是对象的模板蓝图

类比:

  • 类 = 房屋设计图纸
  • 对象 = 根据图纸建造的具体房子

对象(Object)

对象是根据类创建的实例

类比:

复制代码
图纸(类):住宅设计图
对象1:小明家的房子
对象2:小红家的房子
对象3:小刚家的房子

类与对象的关系

复制代码
类(模板)
    ↓ 创建多个
对象1(实例)
对象2(实例)
对象3(实例)
...

定义一个简单的类

基本语法

csharp 复制代码
class 类名
{
    // 字段(属性)
    访问修饰符 数据类型 字段名;

    // 方法
    访问修饰符 返回值类型 方法名()
    {
        // 方法体
    }
}

示例:定义 Person 类

csharp 复制代码
class Person
{
    // 属性(字段)
    public string Name;      // 姓名
    public int Age;          // 年龄
    public string Gender;     // 性别

    // 方法
    public void Introduce()
    {
        Console.WriteLine($"大家好,我叫{Name},今年{Age}岁,性别{Gender}。");
    }
}

代码解析

csharp 复制代码
class Person
{
    // 公开字段,可以从外部访问
    public string Name;  // 存储姓名
    public int Age;      // 存储年龄
    public string Gender; // 存储性别

    // 公开方法,可以被外部调用
    public void Introduce()  // 自我介绍的方法
    {
        // 使用字段输出信息
        Console.WriteLine($"大家好,我叫{Name},今年{Age}岁,性别{Gender}。");
    }
}

创建对象并使用其属性

创建对象

csharp 复制代码
// 语法:类名 对象名 = new 类名();
Person person1 = new Person();
Person person2 = new Person();

访问和修改属性

csharp 复制代码
Person person = new Person();

// 访问属性
Console.WriteLine(person.Name);  // null(未赋值)

// 修改属性
person.Name = "张三";
person.Age = 25;
person.Gender = "男";

// 再次访问
Console.WriteLine(person.Name);   // 张三
Console.WriteLine(person.Age);    // 25
Console.WriteLine(person.Gender); // 男

调用对象的方法

csharp 复制代码
Person person = new Person();
person.Name = "李四";
person.Age = 30;
person.Gender = "女";

// 调用方法
person.Introduce();
// 输出:大家好,我叫李四,今年30岁,性别女。

实践:定义 Person 类并创建对象

csharp 复制代码
using System;

namespace Week7Practice
{
    // 定义 Person 类
    class Person
    {
        // 属性(字段)
        public string Name;
        public int Age;
        public string Gender;
        public string Occupation; // 职业

        // 方法
        public void Introduce()
        {
            Console.WriteLine($"大家好,我叫{Name},今年{Age}岁,性别{Gender}。");
            Console.WriteLine($"我的职业是{Occupation}。");
        }

        public void SayHello()
        {
            Console.WriteLine($"{Name}向你问好:Hello!");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("===== 创建对象 =====\n");

            // 创建第一个 Person 对象
            Person person1 = new Person();
            person1.Name = "张三";
            person1.Age = 28;
            person1.Gender = "男";
            person1.Occupation = "程序员";

            Console.WriteLine("--- 第一个人 ---");
            Console.WriteLine($"姓名:{person1.Name}");
            Console.WriteLine($"年龄:{person1.Age}");
            Console.WriteLine($"性别:{person1.Gender}");
            Console.WriteLine($"职业:{person1.Occupation}");
            person1.Introduce();
            person1.SayHello();

            Console.WriteLine();

            // 创建第二个 Person 对象
            Person person2 = new Person();
            person2.Name = "李四";
            person2.Age = 25;
            person2.Gender = "女";
            person2.Occupation = "设计师";

            Console.WriteLine("--- 第二个人 ---");
            Console.WriteLine($"姓名:{person2.Name}");
            Console.WriteLine($"年龄:{person2.Age}");
            Console.WriteLine($"性别:{person2.Gender}");
            Console.WriteLine($"职业:{person2.Occupation}");
            person2.Introduce();
            person2.SayHello();

            Console.WriteLine("\n===== 多个对象 =====");
            Console.WriteLine($"当前创建了 {person1.Name} 和 {person2.Name} 两个对象");
        }
    }
}

输出:

复制代码
===== 创建对象 =====

--- 第一个人 ---
姓名:张三
年龄:28
性别:男
职业:程序员
大家好,我叫张三,今年28岁,性别男。
我的职业是程序员。
张三向你问好:Hello!

--- 第二个人 ---
姓名:李四
年龄:25
性别:女
职业:设计师
大家好,我叫李四,今年25岁,性别女。
我的职业是设计师。
李四向你问好:Hello!

===== 多个对象 =====
当前创建了 张三 和 李四 两个对象

实践:定义 Student 类

csharp 复制代码
using System;

namespace Week7Practice
{
    // 定义 Student 类
    class Student
    {
        // 属性
        public string Name;      // 姓名
        public int Age;         // 年龄
        public string Grade;     // 年级
        public double Score;     // 成绩

        // 方法
        public void PrintInfo()
        {
            Console.WriteLine($"学生信息:");
            Console.WriteLine($"  姓名:{Name}");
            Console.WriteLine($"  年龄:{Age}");
            Console.WriteLine($"  年级:{Grade}");
            Console.WriteLine($"  成绩:{Score}");
        }

        public bool IsPass()
        {
            return Score >= 60;
        }

        public void PrintGrade()
        {
            if (Score >= 90)
                Console.WriteLine($"成绩等级:优秀");
            else if (Score >= 80)
                Console.WriteLine($"成绩等级:良好");
            else if (Score >= 60)
                Console.WriteLine($"成绩等级:及格");
            else
                Console.WriteLine($"成绩等级:不及格");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("===== 学生信息管理 =====\n");

            // 创建学生对象
            Student student1 = new Student();
            student1.Name = "小明";
            student1.Age = 18;
            student1.Grade = "高三";
            student1.Score = 92.5;

            Student student2 = new Student();
            student2.Name = "小红";
            student2.Age = 17;
            student2.Grade = "高二";
            student2.Score = 58.0;

            // 显示学生信息
            Console.WriteLine("--- 学生1 ---");
            student1.PrintInfo();
            student1.PrintGrade();
            Console.WriteLine($"是否及格:{(student1.IsPass() ? "是" : "否")}");

            Console.WriteLine();

            Console.WriteLine("--- 学生2 ---");
            student2.PrintInfo();
            student2.PrintGrade();
            Console.WriteLine($"是否及格:{(student2.IsPass() ? "是" : "否")}");

            // 计算平均分
            double average = (student1.Score + student2.Score) / 2;
            Console.WriteLine($"\n两人平均分:{average:F2}");
        }
    }
}

输出:

复制代码
===== 学生信息管理 =====

--- 学生1 ---
学生信息:
  姓名:小明
  年龄:18
  年级:高三
  成绩:92.5
成绩等级:优秀
是否及格:是

--- 学生2 ---
学生信息:
  姓名:小红
  年龄:17
  年级:高二
  成绩:58
成绩等级:不及格
是否及格:否

两人平均分:75.25

访问修饰符

访问修饰符控制类成员的可访问性。

常用访问修饰符

修饰符 说明 可访问性
public 公开 可以从任何地方访问
private 私有 只能在当前类内部访问
protected 受保护 只能在当前类和子类中访问
internal 内部 只能在同一程序集中访问

示例

csharp 复制代码
class Person
{
    public string Name;      // 公开,可以外部访问
    private int Age;        // 私有,只能内部访问

    public void SetAge(int age)
    {
        // 可以访问私有字段
        if (age >= 0 && age <= 150)
        {
            Age = age;  // 正确
        }
    }

    public int GetAge()
    {
        return Age;  // 正确
    }
}

class Program
{
    static void Main()
    {
        Person person = new Person();

        person.Name = "张三";  // 正确,public
        // person.Age = 25;      // 错误!private 不能外部访问

        person.SetAge(25);      // 正确,通过公开方法访问
        Console.WriteLine(person.GetAge());
    }
}

类的命名规范

推荐:

  • 使用名词或名词短语
  • 帕斯卡命名法(首字母大写)
  • 单数形式
csharp 复制代码
Person, Student, Car, Book
UserProfile, OrderItem, ShoppingCart

不推荐:

csharp 复制代码
person, student  // 应该用大写开头
Persons, Students  // 应该用单数
DoSomething  // 应该是名词,不是动词

属性 vs 字段

字段(Field)

csharp 复制代码
class Person
{
    public string Name;  // 字段(field)
}

属性(Property)

属性是字段的封装,可以添加验证逻辑。

csharp 复制代码
class Person
{
    private string name;  // 私有字段

    // 属性
    public string Name
    {
        get { return name; }
        set
        {
            if (!string.IsNullOrEmpty(value))
            {
                name = value;
            }
        }
    }
}

简化写法(自动属性):

csharp 复制代码
class Person
{
    public string Name { get; set; }  // 自动属性
    public int Age { get; set; }
}

使用属性

csharp 复制代码
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Person person = new Person();
person.Name = "张三";  // set
Console.WriteLine(person.Name);  // get

实践:带验证的属性

csharp 复制代码
class Person
{
    private int age;

    public int Age
    {
        get { return age; }
        set
        {
            if (value >= 0 && value <= 150)
            {
                age = value;
            }
            else
            {
                Console.WriteLine("年龄必须在 0-150 之间!");
            }
        }
    }
}

Person person = new Person();
person.Age = 25;        // 正常赋值
person.Age = 200;       // 输出:年龄必须在 0-150 之间!
Console.WriteLine(person.Age);  // 输出:25

对象数组

可以创建对象数组来存储多个对象。

csharp 复制代码
using System;

namespace Week7Practice
{
    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }

        public void PrintInfo()
        {
            Console.WriteLine($"{Name} - {Age}岁");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // 创建对象数组
            Person[] people = new Person[3];

            // 初始化每个对象
            people[0] = new Person { Name = "张三", Age = 25 };
            people[1] = new Person { Name = "李四", Age = 30 };
            people[2] = new Person { Name = "王五", Age = 28 };

            Console.WriteLine("=== 人员列表 ===");
            foreach (Person person in people)
            {
                person.PrintInfo();
            }
        }
    }
}

输出:

复制代码
=== 人员列表 ===
张三 - 25岁
李四 - 30岁
王五 - 28岁

对象集合(List)

为什么需要对象集合?

对象数组的问题:

  • 长度固定,创建后不能改变
  • 添加或删除元素需要创建新数组
  • 使用不方便

对象集合的优势:

  • 长度动态,可以自由添加/删除元素
  • 提供丰富的方法(Add、Remove、Find等)
  • 使用简单方便

List 基础

List<T> 是泛型集合,T 表示元素的类型。

csharp 复制代码
// 创建对象的集合
List<Person> people = new List<Person>();

// 添加对象
people.Add(new Person { Name = "张三", Age = 25 });
people.Add(new Person { Name = "李四", Age = 30 });
people.Add(new Person { Name = "王五", Age = 28 });

// 遍历集合
foreach (Person person in people)
{
    person.PrintInfo();
}

List 的常用操作

csharp 复制代码
using System;
using System.Collections.Generic;

namespace Week7Practice
{
    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Occupation { get; set; }

        public void PrintInfo()
        {
            Console.WriteLine($"姓名:{Name},年龄:{Age},职业:{Occupation}");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // 创建 List<Person> 集合
            List<Person> people = new List<Person>();

            Console.WriteLine("===== 添加元素 =====\n");

            // 添加元素
            people.Add(new Person { Name = "张三", Age = 25, Occupation = "程序员" });
            people.Add(new Person { Name = "李四", Age = 30, Occupation = "设计师" });
            people.Add(new Person { Name = "王五", Age = 28, Occupation = "产品经理" });

            Console.WriteLine($"当前人数:{people.Count}");

            Console.WriteLine("\n===== 遍历集合 =====");
            foreach (Person person in people)
            {
                person.PrintInfo();
            }

            Console.WriteLine("\n===== 访问指定元素 =====");
            Console.WriteLine("第一个元素:");
            people[0].PrintInfo();
            Console.WriteLine("最后一个元素:");
            people[people.Count - 1].PrintInfo();

            Console.WriteLine("\n===== 插入元素 =====");
            people.Insert(1, new Person { Name = "赵六", Age = 27, Occupation = "测试工程师" });
            Console.WriteLine($"插入后人数:{people.Count}");
            foreach (Person person in people)
            {
                person.PrintInfo();
            }

            Console.WriteLine("\n===== 删除元素 =====");
            people.RemoveAt(2);  // 删除索引为2的元素(王五)
            Console.WriteLine($"删除后人数:{people.Count}");
            foreach (Person person in people)
            {
                person.PrintInfo();
            }

            Console.WriteLine("\n===== 查找元素 =====");
            Person foundPerson = people.Find(p => p.Name == "李四");
            if (foundPerson != null)
            {
                Console.WriteLine("找到:");
                foundPerson.PrintInfo();
            }

            Console.WriteLine("\n===== 清空集合 =====");
            people.Clear();
            Console.WriteLine($"清空后人数:{people.Count}");
        }
    }
}

输出:

复制代码
===== 添加元素 =====

当前人数:3

===== 遍历集合 =====
姓名:张三,年龄:25,职业:程序员
姓名:李四,年龄:30,职业:设计师
姓名:王五,年龄:28,职业:产品经理

===== 访问指定元素 =====
第一个元素:
姓名:张三,年龄:25,职业:程序员
最后一个元素:
姓名:王五,年龄:28,职业:产品经理

===== 插入元素 =====
插入后人数:4
姓名:张三,年龄:25,职业:程序员
姓名:赵六,年龄:27,职业:测试工程师
姓名:李四,年龄:30,职业:设计师
姓名:王五,年龄:28,职业:产品经理

===== 删除元素 =====
删除后人数:3
姓名:张三,年龄:25,职业:程序员
姓名:赵六,年龄:27,职业:测试工程师
姓名:李四,年龄:30,职业:设计师

===== 查找元素 =====
找到:
姓名:李四,年龄:30,职业:设计师

===== 清空集合 =====
清空后人数:0

List 常用方法

方法 说明 示例
Add(item) 在末尾添加元素 people.Add(person)
Insert(index, item) 在指定位置插入元素 people.Insert(0, person)
Remove(item) 删除指定元素 people.Remove(person)
RemoveAt(index) 删除指定位置的元素 people.RemoveAt(0)
Clear() 清空所有元素 people.Clear()
Count 获取元素数量 int count = people.Count
Find(predicate) 查找符合条件的元素 people.Find(p => p.Age > 20)
FindAll(predicate) 查找所有符合条件的元素 people.FindAll(p => p.Age > 20)
Contains(item) 判断是否包含某元素 bool has = people.Contains(person)
Sort() 对元素排序 people.Sort()

LINQ 方法(Where、GroupBy、OrderBy、Select)

LINQ(Language Integrated Query)提供了一套强大的查询方法,让我们能够方便地对集合进行筛选、排序、分组和转换操作。

注意: 使用 LINQ 方法需要添加命名空间 using System.Linq;

Where - 筛选数据

Where 方法用于根据条件筛选元素,返回符合条件的所有元素。

csharp 复制代码
using System.Linq;

List<Person> people = new List<Person>
{
    new Person { Name = "张三", Age = 25 },
    new Person { Name = "李四", Age = 30 },
    new Person { Name = "王五", Age = 28 },
    new Person { Name = "赵六", Age = 22 }
};

// 筛选年龄大于25的人
var adults = people.Where(p => p.Age > 25);
Console.WriteLine("年龄大于25的人:");
foreach (Person person in adults)
{
    Console.WriteLine($"  {person.Name} - {person.Age}岁");
}

// 筛选名字包含"三"的人
var specificNames = people.Where(p => p.Name.Contains("三"));
Console.WriteLine("\n名字包含'三'的人:");
foreach (Person person in specificNames)
{
    Console.WriteLine($"  {person.Name}");
}

输出:

复制代码
年龄大于25的人:
  李四 - 30岁
  王五 - 28岁

名字包含'三'的人:
  张三
OrderBy / OrderByDescending - 排序

OrderBy 按升序排序,OrderByDescending 按降序排序。

csharp 复制代码
using System.Linq;

List<Person> people = new List<Person>
{
    new Person { Name = "张三", Age = 30 },
    new Person { Name = "李四", Age = 22 },
    new Person { Name = "王五", Age = 28 },
    new Person { Name = "赵六", Age = 25 }
};

// 按年龄升序排序
var sortedByAge = people.OrderBy(p => p.Age);
Console.WriteLine("按年龄升序:");
foreach (Person person in sortedByAge)
{
    Console.WriteLine($"  {person.Name} - {person.Age}岁");
}

// 按年龄降序排序
var sortedByAgeDesc = people.OrderByDescending(p => p.Age);
Console.WriteLine("\n按年龄降序:");
foreach (Person person in sortedByAgeDesc)
{
    Console.WriteLine($"  {person.Name} - {person.Age}岁");

// 按姓名排序
var sortedByName = people.OrderBy(p => p.Name);
Console.WriteLine("\n按姓名排序:");
foreach (Person person in sortedByName)
{
    Console.WriteLine($"  {person.Name}");
}

输出:

复制代码
按年龄升序:
  李四 - 22岁
  赵六 - 25岁
  王五 - 28岁
  张三 - 30岁

按年龄降序:
  张三 - 30岁
  王五 - 28岁
  赵六 - 25岁
  李四 - 22岁

按姓名排序:
  张三
  李四
  王五
  赵六
Select - 转换数据

Select 方法用于将集合中的每个元素转换为新的形式。

csharp 复制代码
using System.Linq;

List<Person> people = new List<Person>
{
    new Person { Name = "张三", Age = 25 },
    new Person { Name = "李四", Age = 30 },
    new Person { Name = "王五", Age = 28 }
};

// 只提取姓名
var names = people.Select(p => p.Name);
Console.WriteLine("所有姓名:");
foreach (string name in names)
{
    Console.WriteLine($"  {name}");
}

// 创建新的对象格式(只包含姓名和年龄)
var simplified = people.Select(p => new { p.Name, p.Age });
Console.WriteLine("\n简化信息:");
foreach (var item in simplified)
{
    Console.WriteLine($"  {item.Name}:{item.Age}岁");
}

// 计算年龄加10岁后的值
var futureAges = people.Select(p => p.Age + 10);
Console.WriteLine("\n10年后的年龄:");
foreach (int age in futureAges)
{
    Console.WriteLine($"  {age}岁");
}

输出:

复制代码
所有姓名:
  张三
  李四
  王五

简化信息:
  张三:25岁
  李四:30岁
  王五:28岁

10年后的年龄:
  35岁
  40岁
  38岁
GroupBy - 分组

GroupBy 方法用于根据某个条件对元素进行分组。

csharp 复制代码
using System.Linq;

class Student
{
    public string Name { get; set; }
    public string Grade { get; set; }
    public double Score { get; set; }
}

List<Student> students = new List<Student>
{
    new Student { Name = "张三", Grade = "高三", Score = 85 },
    new Student { Name = "李四", Grade = "高三", Score = 92 },
    new Student { Name = "王五", Grade = "高二", Score = 78 },
    new Student { Name = "赵六", Grade = "高二", Score = 88 },
    new Student { Name = "孙七", Grade = "高三", Score = 90 }
};

// 按年级分组
var groupedByGrade = students.GroupBy(s => s.Grade);
Console.WriteLine("按年级分组:");
foreach (var group in groupedByGrade)
{
    Console.WriteLine($"\n年级:{group.Key}");
    Console.WriteLine($"  人数:{group.Count()}");
    Console.WriteLine("  学生:");
    foreach (Student student in group)
    {
        Console.WriteLine($"    - {student.Name}({student.Score}分)");
    }
}

输出:

复制代码
按年级分组:

年级:高三
  人数:3
  学生:
    - 张三(85分)
    - 李四(92分)
    - 孙七(90分)

年级:高二
  人数:2
  学生:
    - 王五(78分)
    - 赵六(88分)
组合使用 LINQ 方法

LINQ 方法可以链式调用,实现复杂的查询。

csharp 复制代码
using System.Linq;

List<Person> people = new List<Person>
{
    new Person { Name = "张三", Age = 25 },
    new Person { Name = "李四", Age = 35 },
    new Person { Name = "王五", Age = 28 },
    new Person { Name = "赵六", Age = 40 },
    new Person { Name = "孙七", Age = 30 }
};

// 链式调用:筛选年龄大于25的,按年龄升序排序,只取前3个
var result = people
    .Where(p => p.Age > 25)
    .OrderBy(p => p.Age)
    .Take(3);

Console.WriteLine("年龄大于25的前3人(按年龄升序):");
foreach (Person person in result)
{
    Console.WriteLine($"  {person.Name} - {person.Age}岁");
}

输出:

复制代码
年龄大于25的前3人(按年龄升序):
  王五 - 28岁
  孙七 - 30岁
  李四 - 35岁
LINQ 方法总结
方法 作用 返回类型 示例
Where 筛选符合条件的元素 IEnumerable<T> people.Where(p => p.Age > 18)
OrderBy 升序排序 IOrderedEnumerable<T> people.OrderBy(p => p.Age)
OrderByDescending 降序排序 IOrderedEnumerable<T> people.OrderByDescending(p => p.Age)
Select 转换元素 IEnumerable<TResult> people.Select(p => p.Name)
GroupBy 按条件分组 IEnumerable<IGrouping<TKey, T>> students.GroupBy(s => s.Grade)
Take 取前n个元素 IEnumerable<T> people.Take(5)
Skip 跳过前n个元素 IEnumerable<T> people.Skip(10)
First 取第一个元素 T people.First()
Last 取最后一个元素 T people.Last()
Count() 统计元素数量 int people.Count()
Sum() 求和 numeric people.Sum(p => p.Age)
Average() 求平均值 double people.Average(p => p.Age)
Max() 求最大值 T people.Max(p => p.Age)
Min() 求最小值 T people.Min(p => p.Age)
LINQ 实践:统计学生成绩
csharp 复制代码
using System;
using System.Linq;

namespace Week7Practice
{
    class Student
    {
        public string Name { get; set; }
        public string Grade { get; set; }
        public double Score { get; set; }

        public void PrintInfo()
        {
            Console.WriteLine($"  {Name} - {Grade} - {Score:F1}分");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>
            {
                new Student { Name = "小明", Grade = "高三", Score = 92.5 },
                new Student { Name = "小红", Grade = "高三", Score = 58.0 },
                new Student { Name = "小刚", Grade = "高二", Score = 75.5 },
                new Student { Name = "小丽", Grade = "高二", Score = 88.0 },
                new Student { Name = "小伟", Grade = "高三", Score = 45.0 },
                new Student { Name = "小芳", Grade = "高二", Score = 95.0 }
            };

            Console.WriteLine("===== 学生成绩统计 =====\n");

            // 筛选及格学生
            var passedStudents = students.Where(s => s.Score >= 60);
            Console.WriteLine("--- 及格学生 ---");
            foreach (Student s in passedStudents)
            {
                s.PrintInfo();
            }

            // 按成绩降序排序,取前3名
            var top3Students = students
                .OrderByDescending(s => s.Score)
                .Take(3);
            Console.WriteLine("\n--- 成绩前3名 ---");
            foreach (Student s in top3Students)
            {
                s.PrintInfo();
            }

            // 按年级分组
            var groupedByGrade = students.GroupBy(s => s.Grade);
            Console.WriteLine("\n--- 按年级统计 ---");
            foreach (var group in groupedByGrade)
            {
                double avg = group.Average(s => s.Score);
                Console.WriteLine($"年级:{group.Key}");
                Console.WriteLine($"  人数:{group.Count()}");
                Console.WriteLine($"  平均分:{avg:F2}");
            }

            // 计算最高分和最低分
            double maxScore = students.Max(s => s.Score);
            double minScore = students.Min(s => s.Score);
            double avgScore = students.Average(s => s.Score);
            Console.WriteLine($"\n--- 整体统计 ---");
            Console.WriteLine($"最高分:{maxScore:F1}");
            Console.WriteLine($"最低分:{minScore:F1}");
            Console.WriteLine($"平均分:{avgScore:F2}");

            // 只提取姓名列表
            var names = students.Select(s => s.Name);
            Console.WriteLine($"\n--- 学生名单 ---");
            Console.WriteLine($"所有学生:{string.Join(", ", names)}");
        }
    }
}

输出:

复制代码
===== 学生成绩统计 =====

--- 及格学生 ---
  小明 - 高三 - 92.5分
  小刚 - 高二 - 75.5分
  小丽 - 高二 - 88.0分
  小芳 - 高二 - 95.0分

--- 成绩前3名 ---
  小芳 - 高二 - 95.0分
  小明 - 高三 - 92.5分
  小丽 - 高二 - 88.0分

--- 按年级统计 ---
年级:高三
  人数:3
  平均分:65.17
年级:高二
  人数:3
  平均分:86.17

--- 整体统计 ---
最高分:95.0
最低分:45.0
平均分:75.67

--- 学生名单 ---
所有学生:小明, 小红, 小刚, 小丽, 小伟, 小芳

实践:学生信息管理系统

csharp 复制代码
using System;
using System.Collections.Generic;

namespace Week7Practice
{
    class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Grade { get; set; }
        public double Score { get; set; }

        public void PrintInfo()
        {
            Console.WriteLine($"姓名:{Name},年龄:{Age},年级:{Grade},成绩:{Score:F1}");
        }

        public bool IsPass()
        {
            return Score >= 60;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>();

            Console.WriteLine("===== 学生信息管理系统 =====\n");

            // 添加学生
            Console.WriteLine("--- 添加学生 ---");
            students.Add(new Student { Name = "小明", Age = 18, Grade = "高三", Score = 92.5 });
            students.Add(new Student { Name = "小红", Age = 17, Grade = "高二", Score = 58.0 });
            students.Add(new Student { Name = "小刚", Age = 18, Grade = "高三", Score = 75.5 });
            students.Add(new Student { Name = "小丽", Age = 17, Grade = "高二", Score = 88.0 });
            students.Add(new Student { Name = "小伟", Age = 18, Grade = "高三", Score = 45.0 });

            Console.WriteLine($"已添加 {students.Count} 名学生\n");

            // 显示所有学生
            Console.WriteLine("--- 所有学生信息 ---");
            foreach (Student student in students)
            {
                student.PrintInfo();
            }

            // 计算平均分
            double average = 0;
            foreach (Student student in students)
            {
                average += student.Score;
            }
            average /= students.Count;
            Console.WriteLine($"\n班级平均分:{average:F2}");

            // 找出及格的学生
            Console.WriteLine("\n--- 及格学生 ---");
            List<Student> passedStudents = students.FindAll(s => s.IsPass());
            Console.WriteLine($"及格人数:{passedStudents.Count}");
            foreach (Student student in passedStudents)
            {
                student.PrintInfo();
            }

            // 找出不及格的学生
            Console.WriteLine("\n--- 不及格学生 ---");
            List<Student> failedStudents = students.FindAll(s => !s.IsPass());
            Console.WriteLine($"不及格人数:{failedStudents.Count}");
            foreach (Student student in failedStudents)
            {
                student.PrintInfo();
            }

            // 删除不及格的学生
            Console.WriteLine("\n--- 删除不及格学生 ---");
            foreach (Student student in failedStudents)
            {
                students.Remove(student);
            }
            Console.WriteLine($"剩余学生数:{students.Count}");

            // 最终学生名单
            Console.WriteLine("\n--- 最终学生名单 ---");
            foreach (Student student in students)
            {
                student.PrintInfo();
            }
        }
    }
}

输出:

复制代码
===== 学生信息管理系统 =====

--- 添加学生 ---
已添加 5 名学生

--- 所有学生信息 ---
姓名:小明,年龄:18,年级:高三,成绩:92.5
姓名:小红,年龄:17,年级:高二,成绩:58.0
姓名:小刚,年龄:18,年级:高三,成绩:75.5
姓名:小丽,年龄:17,年级:高二,成绩:88.0
姓名:小伟,年龄:18,年级:高三,成绩:45.0

班级平均分:71.80

--- 及格学生 ---
及格人数:3
姓名:小明,年龄:18,年级:高三,成绩:92.5
姓名:小刚,年龄:18,年级:高三,成绩:75.5
姓名:小丽,年龄:17,年级:高二,成绩:88.0

--- 不及格学生 ---
不及格人数:2
姓名:小红,年龄:17,年级:高二,成绩:58.0
姓名:小伟,年龄:18,年级:高三,成绩:45.0

--- 删除不及格学生 ---
剩余学生数:3

--- 最终学生名单 ---
姓名:小明,年龄:18,年级:高三,成绩:92.5
姓名:小刚,年龄:18,年级:高三,成绩:75.5
姓名:小丽,年龄:17,年级:高二,成绩:88.0

对象数组 vs List

特性 对象数组 List
长度 固定 动态
添加元素 需要创建新数组 直接 Add()
删除元素 需要创建新数组 RemoveAt()
查询 支持索引访问 支持索引访问 + 查找方法
性能 访问快 添加删除快
适用场景 固定数量、高性能 动态数量、灵活操作

何时使用?

使用对象数组:

  • 元素数量固定
  • 追求极致性能
  • 不需要频繁添加/删除

使用 List:

  • 元素数量动态变化
  • 需要频繁添加/删除
  • 需要查找、筛选等功能

本章总结

  • ✅ 理解了面向对象编程(OOP)的概念
  • ✅ 掌握了类和对象的关系
  • ✅ 学会了定义类和创建对象
  • ✅ 理解了属性(字段)和方法
  • ✅ 了解了访问修饰符
  • ✅ 学会了使用对象数组
  • ✅ 掌握了 List 集合的使用
  • ✅ 理解了对象数组和对象集合的区别
相关推荐
云草桑9 小时前
C#.net 分布式ID之雪花ID,时钟回拨是什么?怎么解决?
分布式·算法·c#·.net·雪花id
步步为营DotNet10 小时前
深度解析.NET中IEnumerable<T>.SelectMany:数据扁平化与复杂映射的利器
java·开发语言·.net
csdn_aspnet10 小时前
C# .NET 常用算法深度解析,从LINQ到并发的实战
c#·.net·linq
无风听海19 小时前
.NET Framework 4.8 内部日志功能
.net
gjxDaniel21 小时前
VB.NET编程语言入门与常见问题
.net·vb.net
aiyo_21 小时前
深入浅出DOTNET技术原理
.net·.net core
Traced back21 小时前
# Windows窗体 + SQL Server 自动清理功能完整方案优化版
数据库·windows·.net
今晚打老虎z1 天前
必应壁纸接口
.net
Traced back1 天前
Windows窗体应用 + SQL Server 自动清理功能方案:按数量与按日期双模式
数据库·windows·c#·.net