我有一个基本设计,包括以下类和接口:
IRepository<TEntity>
界面,Repository<TEntity>
基类,TenantRepository
类。由于接口继承的所有东西都有定义的公共访问权限,因此我可以调用Add
方法(基类)
_tenantRepository.Add(new Tenant { Name = "blah" } );
我应该在Create
TenantRepository
方法
_tenantRepository.Create("blah");
如果我能够将Add
方法定义为受保护以便客户端代码无法访问该方法,那将是很好的,但是这是不允许的,因为它是一个简单的事实,它是在接口中定义的方法,必须有公共访问权限。
或者我可以将方法命名为相同的,这样我实际上覆盖了具体类中的实现。这会阻止客户端代码直接调用Repository.Add
。但在某些情况下,我真的想阻止客户端代码调用基类中定义的方法。
另一种选择可能是写下这样的东西:
new protected void Add(Tenant tenant)
{
}
但这让我颤抖(当我开始重构方法名称时,它会很快崩溃。)
有没有更好的方法来实现这一目标?
界面:
public interface IRepository<TEntity> : IDisposable where TEntity : IEntity
{
IQueryable<TEntity> GetAll();
void Delete(TEntity entity);
void Add(TEntity entity);
}
基类的一小部分:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
protected IDbContext Context;
public Repository(IDbContext context)
{
Context = context;
}
public void Add(TEntity entity)
{
DbSet.Add(entity);
}
// Left out other, for this question irrelevant, method implementations
}
最后是TenantRepository
public class TenantRepository : Repository<Tenant>
{
public TenantRepository(IDbContext context)
: base(context)
{
}
public Tenant Create(string tenantName)
{
var tenant = new Tenant
{
Name = tenantName,
Guid = Guid.NewGuid().ToString()
};
if (Exists(tenant.Name))
{
throw new TenantAlreadyExistsException(tenant.Name);
}
Add(tenant);
return tenant;
}
// Left out other, for this question irrelevant, method implementations
}
答案 0 :(得分:1)
一种解决方案是使TenantRepository不从您的存储库继承。毕竟,听起来它们具有不同的功能(您希望创建而不是添加。)
如果你走这条路,Repository就会成为你的TenenantRepository类的私有成员,因为只知道应该调用哪些存储库方法。
答案 1 :(得分:1)
您可以使用explicit interface implementation隐藏添加方法。基本上,在Repository中,执行以下操作:
public IRepository<Tenant>.Add(Tenant toAdd)
{
//do the add
}
这只能通过转换到IRepository来获得。
答案 2 :(得分:0)
如果TenantRepository
需要Add
检查Tenant
的唯一性,则应在Add
方法本身中包含该逻辑。
您应该在您的TenantRepository中的基础Add
类Repository
和virtual
中设置override
,以便它在Create
方法中执行您现在的唯一性检查
public interface IRepository<T>
{
void Add(T entity);
}
public class Repository<T> : IRepository<T>
{
// mocking Add so it works without a DB
public virtual void Add(T entity)
{
Console.WriteLine("{0} added", entity.ToString());
}
}
public class Tenant
{
public string Name{get; private set;}
public Tenant(string Name)
{
this.Name=Name;
}
public override string ToString() {return this.Name;}
}
public class TenantRepository : Repository<Tenant>
{
// Add is virtual, so it can be overridden by TenantRepository
public override void Add(Tenant entity)
{
// this represents your uniqueness check
if(entity.Name=="Paolo") throw new Exception();
base.Add(entity); // calling Add on the base Repository
}
//you can now avoid having Create or making it just call Add
public Tenant Create(Tenant entity)
{
this.Add(entity);
return entity;
}
}