目录

泛型接口 + 泛型约束(Generic Constraint)

基于以下代码来解释泛型接口和泛型约束

public interface IRepository<T> where T : BaseEntity

IRepository 是一个“泛型接口”

意思是:

这个接口不处理具体类型,而是处理“某种类型 T 的数据”。

例如:

  • IRepository<User>
  • IRepository<Product>
  • IRepository<Order>

都可以是这个接口的不同“版本”。

**where T : BaseEntity **是泛型约束

意思是:

只有继承自 BaseEntity 的类型才能作为 T 来使用。

也就是:

public class User : BaseEntity { }
public class Product : BaseEntity { }

// OK
IRepository<User>
IRepository<Product>

// ❌ 不行
IRepository<string>     // 报错:string 没继承 BaseEntity
IRepository<int>        // 不行

为什么要加这个约束?

因为接口内部(或仓储逻辑)可能会需要访问 BaseEntity 的属性,比如:

public interface BaseEntity
{
    int Id { get; set; }
}

仓储逻辑就可以安全地使用 Id,例如:

T GetById(int id);

武侠比喻:泛型约束 = 入门条件(拜师条件)

想象:

BaseEntity = “入门弟子”

所有继承它的类型 = “入门弟子都学过基础武学(例如都有 Id 身份令牌)”

而:

IRepository<T> where T : BaseEntity = “此门派的武功(IRepository)只传授给入门弟子”

也就是:

你必须至少是门派弟子(继承 BaseEntity)才能学习存储管理这门功法。

所以:

  • User 是继承 BaseEntity 的弟子 → 合格
  • Product 是继承 BaseEntity 的弟子 → 合格
  • string 是街边小孩,不是该门派弟子 → ❌ 不合格
  • int 是石头 → ❌ 也不合格

为什么需要这种写法(实际工程意义)

因为在 Repository(仓储模式)中:

  • 所有实体(User、Product、Order…)都必须有基本属性,比如 Id
  • 所有数据库操作都依赖这个基础属性
  • 如果没有约束,泛型 T 里面可能没有 Id,代码会崩

这个约束能让编译器保护你:

  • 有 Id

  • 有 CreateTime

  • 有 UpdateTime

    这些都是 BaseEntity 可能拥有的)

示例:仓储接口可能这样写

public interface IRepository<T> where T : BaseEntity
{
    T GetById(int id);
    void Add(T entity);
    void Delete(T entity);
}

没有 where T : BaseEntity 的话,你写:

entity.Id

就会报错,因为 T 可能没有 Id。

总结

IRepository<T> where T : BaseEntity
是一个泛型仓储接口,要求 T 必须是某个“基础实体类”的子类,这可以保证仓储操作可以安全使用共通属性(例如 Id)。