← SEARCHABLE ARCHIVE
C# · 2026-07-25

从 C# 基础到掌握 — 第 4 集

将角色分为继承、接口和泛型

INTERACTIVE READING MODE →

该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。

当多个类需要提供相同的行为时,可以使用继承和接口。 向外界呈现什么样的契约比将事物捆绑在一起更重要。

通过界面表达角色

public interface IDamageable
{
    bool IsAlive { get; }
    void TakeDamage(int amount);
}

public sealed class Monster : IDamageable
{
    public int Health { get; private set; } = 100;
    public bool IsAlive => Health > 0;

    public void TakeDamage(int amount)
    {
        Health = Math.Max(0, Health - amount);
    }
}

对于攻击代码,你只需要知道IDamageable,而不是整个Monster。 您稍后可以使用相同的代码添加训练稻草人或可破坏的盒子。

继承用于 is-a 关系

public abstract class Skill
{
    public string Name { get; }

    protected Skill(string name) => Name = name;
    public abstract void Execute(IDamageable target);
}

public sealed class FireSkill : Skill
{
    public FireSkill() : base("Fire") { }

    public override void Execute(IDamageable target)
    {
        target.TakeDamage(30);
    }
}

继承也继承了基类的状态和规则。 如果您只是为了重用几行代码而创建深度继承结构,则对父级的更改将影响所有子级。

使用泛型维护类型安全

public sealed class Registry<T> where T : class
{
    private readonly Dictionary<int, T> values = new();

    public void Add(int id, T value) => values.Add(id, value);

    public T? Find(int id)
    {
        return values.TryGetValue(id, out T? value) ? value : null;
    }
}

Registry<Monster>和Registry<Skill>使用相同的存储规则,但它们的值不能混合。 约束 where 告诉编译器 T 必须提供哪些属性。

接口表达角色,继承表达公共基础,泛型表达不同类型的相同规则。 与其同时使用这三个函数中的许多函数,不如先创建最小的合约并在必要时进行扩展更安全。