控制对从基类继承的方法的访问,从接口继承

时间:2013-02-24 13:53:15

标签: c#

我有一个基本设计,包括以下类和接口:

  • 一个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 
}

3 个答案:

答案 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中的基础AddRepositoryvirtual中设置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;
    }
}