C# 面向对象编程

2 minBeginner2026/6/14

类与对象、构造函数、继承、多态、抽象类与接口、属性与索引器、运算符重载、记录类型(record)

1. 与对象

1.1 的定义

public class Person
{
    // 字段
    private string _name;
    private int _age;

    // 属性
    public string Name
    {
        get => _name;
        set => _name = value ?? throw new ArgumentNullException(nameof(value));
    }

    public int Age
    {
        get => _age;
        set => _age = value >= 0 ? value : throw new ArgumentOutOfRangeException();
    }

    // 自动属性
    public string Email { get; set; } = string.Empty;

    // init 属性(C# 9+,仅初始化时赋值)
    public string Address { get; init; } = string.Empty;

    // 计算属性
    public bool IsAdult => Age >= 18;

    // 构造函数
    public Person(string name, int age)
    {
        _name = name;
        _age = age;
    }

    // 方法
    public string Greet() => $"你好,我是{Name},今年{Age}岁";

    // 方法重载
    public string Greet(string greeting) => $"{greeting},我是{Name}";

    public override string ToString() => $"{Name} ({Age})";
}

1.2 对象创建与初始化

// 构造函数 + 对象初始化器
var person = new Person("张三", 25)
{
    Email = "zhangsan@example.com",
    Address = "北京市"
};

// init 属性只能在初始化时设置
// person.Address = "上海"; // 编译错误!

// with 表达式(record 类型专用)
var record1 = new PersonRecord("李四", 30);
var record2 = record1 with { Age = 31 };

// 目标类型 new(C# 9+)
Person p = new("王五", 28);
List<Person> people = [new("赵六", 22), new("钱七", 35)];

1.3 静态成员

public class MathHelper
{
    // 静态字段
    public static int InstanceCount { get; private set; }

    // 静态构造函数(仅执行一次)
    static MathHelper()
    {
        InstanceCount = 0;
    }

    // 静态方法
    public static double CircleArea(double radius) => Math.PI * radius * radius;

    // 静态类(不能实例化)
}

public static class StringExtensions
{
    public static bool IsNullOrEmpty(this string? str) =>
        string.IsNullOrEmpty(str);
}

2. 构造函数

2.1 构造函数

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }

    // 无参构造函数
    public Product()
    {
        Name = "未知商品";
        Price = 0;
        Category = "未分类";
    }

    // 参数化构造函数
    public Product(string name, decimal price)
    {
        Name = name;
        Price = price;
        Category = "未分类";
    }

    // 构造函数链
    public Product(string name, decimal price, string category) : this(name, price)
    {
        Category = category;
    }
}

// C# 12 主构造函数
public class Service(ILogger logger, IConfiguration config)
{
    public void DoWork()
    {
        logger.LogInformation("执行工作...");
        var value = config["Key"];
    }

    // 主构造函数参数可变
    public void SetLogger(ILogger newLogger) => logger = newLogger;
}

3. 继承

3.1 基本继承

// 基类
public class Animal
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Animal(string name, int age)
    {
        Name = name;
        Age = age;
    }

    // virtual 允许子类重写
    public virtual string Speak() => $"{Name}发出了声音";

    // sealed 阻止进一步重写
    public sealed string GetInfo() => $"{Name}, {Age}岁";
}

// 派生类
public class Dog : Animal
{
    public string Breed { get; set; }

    // 调用基类构造函数
    public Dog(string name, int age, string breed) : base(name, age)
    {
        Breed = breed;
    }

    // override 重写虚方法
    public override string Speak() => $"{Name}汪汪叫!";

    // 方法隐藏(不推荐,应使用 override)
    public new string GetInfo() => $"{Name} ({Breed}), {Age}岁";
}

3.2 多态

// 运行时多态
Animal animal = new Dog("旺财", 3, "金毛");
Console.WriteLine(animal.Speak()); // "旺财汪汪叫!"

// 多态集合
List<Animal> animals =
[
    new Dog("旺财", 3, "金毛"),
    new Cat("咪咪", 2, "橘猫"),
    new Bird("小鸟", 1, "鹦鹉")
];

foreach (var a in animals)
{
    Console.WriteLine(a.Speak()); // 每个对象调用各自实现
}

// is 模式匹配
foreach (var a in animals)
{
    switch (a)
    {
        case Dog d: Console.WriteLine($"狗: {d.Breed}"); break;
        case Cat c: Console.WriteLine($"猫: {c.Color}"); break;
        case Bird b: Console.WriteLine($"鸟: {b.Species}"); break;
    }
}

4. 抽象类接口

4.1 抽象类

public abstract class Shape
{
    public string Color { get; set; }

    protected Shape(string color) => Color = color;

    // 抽象方法:子类必须实现
    public abstract double Area();
    public abstract double Perimeter();

    // 虚方法:子类可选重写
    public virtual string Describe() =>
        $"{GetType().Name} (颜色: {Color}, 面积: {Area():F2})";
}

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

    public Circle(double radius, string color) : base(color) => Radius = radius;

    public override double Area() => Math.PI * Radius * Radius;
    public override double Perimeter() => 2 * Math.PI * Radius;
}

4.2 接口

// 接口定义契约
public interface IReadable
{
    string Read();
}

public interface IWritable
{
    void Write(string content);
}

// 接口默认实现(C# 8+)
public interface ILogger
{
    void Log(string message);

    // 默认实现
    void LogWarning(string message) => Log($"[WARN] {message}");
    void LogError(string message) => Log($"[ERROR] {message}");
}

// 多接口实现
public class FileStorage : IReadable, IWritable, ILogger
{
    private readonly string _path;

    public FileStorage(string path) => _path = path;

    public string Read() => File.ReadAllText(_path);
    public void Write(string content) => File.WriteAllText(_path, content);
    public void Log(string message) => Console.WriteLine(message);
}

// C# 13 扩展类型(预览)
// 允许向现有类型添加方法而不修改原始定义

4.3 抽象类 vs 接口

特性抽象类接口
多继承单继承多实现
构造函数
字段可以有仅静态常量
方法实现可以有具体实现C# 8+ 可有默认实现
访问修饰符任意默认 public
版本控制添加方法不破坏子添加方法可能破坏实现
适用场景”是什么”(IS-A)“能做什么”(CAN-DO)

5. 属性与索引器

5.1 属性进阶

public class Temperature
{
    private double _celsius;

    public double Celsius
    {
        get => _celsius;
        set => _celsius = value;
    }

    // 派生属性
    public double Fahrenheit
    {
        get => _celsius * 9 / 5 + 32;
        set => _celsius = (value - 32) * 5 / 9;
    }

    // required 属性(C# 11)
    public required string Unit { get; init; }
}

// 接口属性
public interface INamed
{
    string Name { get; }          // 只读
    string? Description { get; set; } // 可读写
}

5.2 索引器

public class Matrix
{
    private readonly double[,] _data;

    public int Rows => _data.GetLength(0);
    public int Cols => _data.GetLength(1);

    public Matrix(int rows, int cols)
    {
        _data = new double[rows, cols];
    }

    // 索引器
    public double this[int row, int col]
    {
        get => _data[row, col];
        set => _data[row, col] = value;
    }
}

var matrix = new Matrix(3, 3);
matrix[0, 0] = 1.0;
matrix[1, 1] = 2.0;
var value = matrix[2, 2];

6. 运算符重载

public class Vector
{
    public double X { get; }
    public double Y { get; }

    public Vector(double x, double y) => (X, Y) = (x, y);

    // 二元运算符
    public static Vector operator +(Vector a, Vector b) =>
        new(a.X + b.X, a.Y + b.Y);

    public static Vector operator -(Vector a, Vector b) =>
        new(a.X - b.X, a.Y - b.Y);

    // 一元运算符
    public static Vector operator -(Vector v) =>
        new(-v.X, -v.Y);

    // 标量乘法
    public static Vector operator *(Vector v, double scalar) =>
        new(v.X * scalar, v.Y * scalar);

    public static Vector operator *(double scalar, Vector v) => v * scalar;

    // 比较运算符(需成对重载)
    public static bool operator ==(Vector a, Vector b) =>
        a.X == b.X && a.Y == b.Y;

    public static bool operator !=(Vector a, Vector b) => !(a == b);

    // 必须重写 Equals 和 GetHashCode
    public override bool Equals(object? obj) =>
        obj is Vector v && this == v;

    public override int GetHashCode() => HashCode.Combine(X, Y);

    // 隐式/显式转换
    public static implicit operator Vector((double x, double y) tuple) =>
        new(tuple.x, tuple.y);

    public override string ToString() => $"({X}, {Y})";
}

// 使用
var v1 = new Vector(1, 2);
var v2 = new Vector(3, 4);
var v3 = v1 + v2;           // (4, 6)
var v4 = v1 * 2.0;          // (2, 4)
Vector v5 = (5.0, 6.0);     // 元组隐式转换

7. 记录类型 (Record)

Record 是 C# 9 引入的不可变引用型,专为值语义设计:

7.1 记录类型定义

// 位置记录(最简洁)
public record Person(string Name, int Age);

// 可添加额外成员
public record Student(string Name, int Age, string School) : Person(Name, Age)
{
    public double GPA { get; init; }
    public string Grade => GPA switch
    {
        >= 3.7 => "A",
        >= 3.0 => "B",
        >= 2.0 => "C",
        _ => "D"
    };
}

// record struct(C# 10,值类型记录)
public record struct Point(double X, double Y)
{
    public double Distance => Math.Sqrt(X * X + Y * Y);
}

// readonly record struct
public readonly record struct Money(decimal Amount, string Currency);

7.2 记录类型特性

var p1 = new Person("张三", 25);
var p2 = new Person("张三", 25);

// 值相等性(与 class 不同!)
Console.WriteLine(p1 == p2);       // True(class 为 False)
Console.WriteLine(p1.Equals(p2));  // True

// with 表达式(非破坏性修改)
var p3 = p1 with { Age = 26 };
Console.WriteLine(p3); // Person { Name = 张三, Age = 26 }

// 解构
var (name, age) = p1;
Console.WriteLine($"{name}, {age}"); // 张三, 25

// ToString 自动生成
Console.WriteLine(p1); // Person { Name = 张三, Age = 25 }

7.3 Record vs Class 选择

场景推荐原因
DTO / 数据传输record值相等、不可变、with 表达式
值对象recordreadonly record struct值语义
领域实体class需要可变状态和引用相等
配置对象record不可变,易于克隆
性能敏感的小对象readonly record struct避免堆分配