C# 泛型 Class 与接口

C# Generics Class vs Interface

我有一个通用存储库,用于更新我的 EF 数据上下文,如下所示(为简洁起见缩短):

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    IQueryable<T> Find(Expression<Func<T, bool>> filter = null);
}

public class Repository<TEntity, TContext> : IRepository<TEntity>
    where TEntity : class
    where TContext : DbContext
{
    public IUnitOfWork UnitOfWork { get; set; }
    public TContext DataContext { get; set; }

    public Repository(IUnitOfWork unitOfWork, TContext dataContext)
    {
        UnitOfWork = unitOfWork;
        DataContext = dataContext;
    }

    public virtual void Add(TEntity entity)
    {
        DataContext.Set<TEntity>().Add(entity);
    }

    public virtual void Update(TEntity entity)
    {
        DataContext.Set<TEntity>().Attach(entity);
        DataContext.Entry(entity).State = EntityState.Modified;
    }

    public virtual void Delete(TEntity entity)
    {
        if (DataContext.Entry(entity).State == EntityState.Detached)
            DataContext.Set<TEntity>().Attach(entity);
        DataContext.Set<TEntity>().Remove(entity);
    }

    public IQueryable<TEntity> Find(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter = null)
    {
        IQueryable<TEntity> query = DataContext.Set<TEntity>();

        if (filter != null)
            query = query.Where(filter);

        return query;
    }
}

我想创建一个 IArchiveOnlyRepository 以用于实现我的 IArchiveable 接口的实体。我希望这会起作用:

public interface IArchiveable
{
    bool IsArchived { get; set; }
    DateTime? ArchivedOn { get; set; }
    string ArchivedBy { get; set; }
}

public interface IArchiveOnlyRepository<T> where T : IArchiveable
{
    void Add(T entity);
    void Update(T entity);
    void Archive(T entity);
    IQueryable<T> Find(Expression<Func<T, bool>> filter = null);
}

public class ArchiveOnlyRepository<TEntity, TContext> : IArchiveOnlyRepository<TEntity>
    where TEntity : IArchiveable
    where TContext : DbContext
{
    public IUnitOfWork UnitOfWork { get; set; }
    public TContext DataContext { get; set; }

    public ArchiveOnlyRepository(IUnitOfWork unitOfWork, TContext dataContext)
    {
        UnitOfWork = unitOfWork;
        DataContext = dataContext;
    }

    public virtual void Add(TEntity entity)
    {
        DataContext.Set<TEntity>().Add(entity);
    }

    public virtual void Update(TEntity entity)
    {
        DataContext.Set<TEntity>().Attach(entity);
        DataContext.Entry(entity).State = EntityState.Modified;
    }

    public virtual void Archive(TEntity entity)
    {
        if (DataContext.Entry(entity).State == EntityState.Detached)
            DataContext.Set<TEntity>().Attach(entity);
        entity.IsArchived = true;
        entity.ArchivedOn = DateTime.UtcNow;
        entity.ArchivedBy = UnitOfWork.UserName;
    }

    public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>)
    {
        IQueryable<TEntity> query = DataContext.Set<TEntity>();

        if (filter != null)
            query = query.Where(filter);

        return query;
    }
}

不幸的是,以下几行:

DataContext.Set<TEntity>()...

生成以下错误:

The Type 'TEntity' must be a reference type in order to use it as parameter 'TEntity'

我如何定义这个通用存储库以确保 T 是实现 IArchiveable 的 class?

您只需要将 class 类型约束放回:

where TEntity : class, IArchiveable

你只需要将TEntity约束为class(引用类型)

public interface IArchiveOnlyRepository<T> where T : IArchiveable, class
...

public class ArchiveOnlyRepository<TEntity, TContext> : IArchiveOnlyRepository<TEntity>
   where TEntity : IArchiveable, class
   where TContext : DbContext
....

改变一下

where TEntity : IArchiveable

where TEntity : class, IArchiveable