类在c#中类包含两种成员数据成员属性/字段用来描述“有什么”函数描述可以做什么// 1. 定义类 public class Person { // 字段存储数据 private string name;// 属性对字段的保护性访问 public string Name { get { return name; } set { name value; } } // 自动属性简化写法 public int Age { get; set; } // 构造函数专门用来创建对象时初始化 public Person(string name, int age) { Name name; Age age; } // 方法行为 public void SayHello() { Console.WriteLine($你好我是{Name}今年{Age}岁。); } Person person1 new Person(张三, 25); person1.SayHello(); // 输出你好我是张三今年25岁。Person person2 new Person(李四, 30);特性1.封装通过private、public、protected等访问修饰符把内部数据隐藏起来只暴露必要的方法给外部。2.继承一个类子类可以继承另一个类父类的属性和方法并扩展自己的新功能。3.多态同一个方法名在不同的子类中有不同的实现。类是引用类型可以进行实例化想要创建一个类的实例需要使用 new 关键字Student Object new Student();静态类使用static关键字来修饰 不可以进行实例化对象 静态类是密封的不可以被继承 静态类也可以有构造函数 但是他是无参且不可以手动调用的静态类中字段 属性 方法都必须带上static关键字public class Student { public string Name { get; set; } // 实例属性 public void SayHello() { } // 实例方法 } // 使用Student s new Student(); s.SayHello();// 2. 静态类直接点{ // 必须全部静态 public static double PI 3.14159; public static int Add(int a, int b) { return a b; } } // 使用直接 类名.方法名 int result MathHelper.Add(3, 5); 构造函数构造函数是一种特殊的方法名字必须跟类名完全一样区分大小写。绝对没有返回值连void都不能写。在你new的时候它会被系统自动调用接续我们之前的Person类我们来看构造函数怎么给字段和属性赋初值{ // 字段私有数据 private string _name; // 属性公开入口 public int Age { get; set; }// ---------- 1. 无参数构造函数默认构造 ---------- // 如果没写任何构造函数系统会免费送一个空的。 // 但如果你写了带参的这个就需要手动写出来如果需要的话。 public Person() { _name 匿名用户; Age 18; // 给属性赋默认值 Console.WriteLine(1. 一个默认的Person诞生了); } // ---------- 2. 带参数构造函数最常用 ---------- // 强制外部在 new 的时候必须传入姓名和年龄 public Person(string name, int age) { _name name; // 通过参数给私有字段赋值 Age age; // 通过参数给属性赋值 Console.WriteLine($2. 具体用户 {name} 初始化完成); }// 触发无参构造 Person p1 new Person(); // 输出1. 一个默认的Person诞生了Person p2 new Person(张三, 25); // 输出2. 具体用户 张三 初始化完成构造函数也有静态构造函数和私有构造函数构造函数定义了数据怎么被初始化。定义重载Overloading它是什么在同一作用域内多个方法或构造函数具有相同名称但不同参数类型、数量或顺序的能力。类比同名不同调。比如“煮”煮饭、煮水、煮菜——动作相同但输入参数不同。重载的关键规则必须同名。参数列表必须不同类型、数量或参数顺序。注意泛型参数也算。仅返回值类型不同不算重载编译器无法区分因为调用时可能忽略返回值。仅参数修饰符不同如ref、out、in可以构成重载。可在类、结构或接口中发生。必须参数不同参数的类型、个数、顺序至少有一样不同。返回类型不同不算重载提供多种不同参数的入口重写. 重写 vs 重载一次性分清两者极容易混淆比较维度重写 (Override)重载 (Overload)发生位置父子类继承体系之间同一个类中方法名必须完全相同必须完全相同参数列表必须完全相同签名一致必须不同类型、个数、顺序返回值必须相同协变返回除外无关可以不同关键字需要virtual/override不需要特殊关键字绑定时机运行时绑定动态多态编译时绑定静态多态目的改变父类的既定行为提供多种便捷调用方式在 C# 中“重写”最核心的含义是指方法重写Method Overriding即子类使用override关键字重新实现父类中定义的虚方法或抽象方法从而实现运行时多态。这是最标准的“重写”。父类必须使用virtual虚方法或abstract抽象方法标记子类才能使用override重写。{ // 使用 virtual 标记允许子类重写 public virtual void Speak() { Console.WriteLine(动物发出声音); } }{ // 使用 override 重写父类方法 public override void Speak() { Console.WriteLine(汪汪); } }Animal myPet new Dog(); myPet.Speak(); // 输出汪汪重写的硬性规则方法签名返回值类型、方法名、参数列表必须完全一致。不能重写static或非virtual/abstract的方法。访问修饰符不能降低如父类是protected子类不能改成private。重写抽象方法abstract若父类方法是abstract子类必须使用override实现它除非子类也是抽象类。{ public abstract double GetArea(); // 无方法体强制子类重写 }{ private double _radius; public override double GetArea() Math.PI * _radius * _radius; }高级用法密封重写sealed override如果不想让子类再次重写该方法可以在override前加sealed终止继承链。{ public sealed override void Speak() // 阻止更下一级的子类重写 { Console.WriteLine(小奶狗嗷嗷叫); } }结构体结构体是隐式密封sealed的你不能继承另一个结构体或类。结构体不支持虚成员virtual/abstract因为虚方法依赖继承链和多态而值类型在栈上分配不涉及类型指针Type Pointer无法实现动态分派。结构体可以实现接口但不是“重写”结构体可以像类一样实现接口如IDisposable、IComparable。实现接口方法时使用的关键字是implements隐式或显式实现不需要加override因为这属于“实现约定”而非“重写父类逻辑”。{ public void Dispose() // 这里不加 override { // 清理逻辑 } }抽象类抽象类abstract class是“重写Override”机制的核心应用场景。它与结构体struct恰好相反——结构体不能继承而抽象类生来就是为了被继承和重写。在抽象类中重写主要分为两种情况强制重写抽象方法和可选重写虚方法。1. 重写抽象方法abstract→override—— 强制实现这是最标准的用法。父类使用abstract定义方法时不提供任何实现子类除非也是抽象类必须使用override提供具体逻辑。{ // 抽象方法没有方法体强制子类重写 public abstract void MakeSound(); // 抽象属性同理 public abstract string Species { get; }{ // 必须使用 override 实现否则编译报错 public override void MakeSound() { Console.WriteLine(汪汪); }public override string Species 犬科;}abstract方法只能存在于抽象类中。子类重写时override方法的访问修饰符不能降低父类protected子类不能是private。返回值类型、方法名、参数列表必须完全一致。重写虚方法virtual→override—— 可选覆盖如果父类方法已有默认实现但允许子类按需修改就用virtual。子类可以选择不重写沿用父类逻辑也可以选择重写。{ // 虚方法有默认实现子类可重写也可不重写 public virtual void Eat() { Console.WriteLine(动物正在进食...); } }public class Cat : Animal { // 可选觉得父类逻辑不符合自己重写 public override void Eat() { Console.WriteLine(猫正在优雅地吃鱼...); } }public class Fish : Animal { // 不重写调用时会沿用父类的 动物正在进食... }继承链中的“密封重写”sealed override如果在抽象类的派生类中重写了方法并且不想让再下一级的子类继续重写可以在override前加上sealed。接口. 标准接口实现最常用—— 不加override无论是隐式实现还是显式实现都不需要使用override。public interface IAnimal { void Speak(); string Name { get; set; } }// 隐式实现直接 public 方法 public class Dog : IAnimal { // 注意这里没有 override只是 public 实例方法 public void Speak() { Console.WriteLine(汪汪); }public string Name { get; set; }}// 显式实现通过接口名调用也不能加 override public class Cat : IAnimal { // 显式实现不加 override且不能加 public void IAnimal.Speak() { Console.WriteLine(喵喵); }string IAnimal.Name { get; set; } // 显式属性同理{ void Speak(); string Name { get; set; } }// 隐式实现直接 public 方法{ // 注意这里没有 override只是 public 实例方法 public void Speak() { Console.WriteLine(汪汪); }public string Name { get; set; }// 显式实现通过接口名调用也不能加 override{ // 显式实现不加 override且不能加 public void IAnimal.Speak() { Console.WriteLine(喵喵);string IAnimal.Name { get; set; } // 显式属性同理{ // 接口中的默认实现C# 8.0 void Log(string message) { Console.WriteLine($默认日志{message}); } }public class FileLogger : ILogger { // 这里没有 override只是重新实现了接口成员 public void Log(string message) { Console.WriteLine($写入文件{message}); } }// 如果不想覆盖直接继承默认实现类里可以什么都不写。