문제

I am trying to define the appropriate interfaces and classes to create a repository interface and a base repository class that does common things every repository will need. Then I also want to define a repository for a specific entity type which is also defined in an interface of it's own.

So far I've come up with the following:

// The repository interface:

/// <summary>
/// Defines the methods of the base repository
/// </summary>
/// <typeparam name="TEntity">An entity class</typeparam>
public interface IRepository<TEntity> where TEntity : class
{
    /// <summary>
    /// Retrieves all the entities
    /// </summary>
    /// <returns>A query able set of entities</returns>
    IQueryable<TEntity> Get();
}

// An abstract implementation of it, which all repositories will inherit from:

/// <summary>
/// Represents the base repository from which all database bound repositories inherit
/// </summary>
/// <typeparam name="TEntity">The entity type this repository handles</typeparam>
public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    /// <summary>
    /// Retrieves all the entities
    /// </summary>
    /// <returns>A query able set of entities</returns>
    public virtual IQueryable<TEntity> Get()
    {
        return this.Context.Set<TEntity>();
    }
}

A specific interface for the user entity:

/// <summary>
/// Represents a user
/// </summary>
public class User
{
    public string Login { get; set; }
    public string Password { get; set; }
}

/// <summary>
/// Defines the interface for user repository implementations
/// </summary>
/// <typeparam name="TEntity">A user entity</typeparam>
public interface IUserRepository<TEntity> : IRepository<TEntity> where TEntity : User
{
    void Authenticate(TEntity user);
}

// and it's implementation:

/// <summary>
/// Represents a database bound repository that handles user entities
/// </summary>
/// <typeparam name="TEntity">A user entity</typeparam>
public class UserRepository<TEntity> : BaseRepository<TEntity>, IUserRepository<TEntity> where TEntity : User
{
    public void Authenticate(TEntity user)
    {
        // do some stuff here
    }
}

The above works fine but in order to instantiate a UserRepository I have to write var users = new UserRepository<User>()

It is obvious that the generic in UserRepository can only be of type User, so I would like to find a way not having to explicitly write this. I'd like to be able to write var users = new UserRepository() instead.

Also, while writing tests, I have to create mocks of the IUserRepository like this:

var usersMock = new Mock<IUserRepository<User>>();

Here I'd also like to be able to write something like this:

var usersMock = new Mock<IUserRepository>();

This may be a XY problem, so I am open to different overall implementation suggestions.

도움이 되었습니까?

해결책

You could implement the specific interfaces:

public interface IUserRepository : IRepository<User>
{
    void Authenticate(Useruser);
}

// and it's implementation:

public class UserRepository : BaseRepository<User>, IUserRepository
{
    public void Authenticate(User user)
    {
        // do some stuff here
    }
}

Your interfaces can have generic type parameters, but when you implement an interface you can specify these arguments. Your implementation does not need to be generic as well

다른 팁

If you are always using a specific class or interface for a certain class' inheritance/implementation, then you do not need to tack on generics to it.

Here's an example below and hopefully what you were asking for:

public interface IUserRepository : IRepository<IUser>
{
    void Authenticate(IUser user);
}

public class UserRepository : BaseRepository<User>, IUserRepository
{
    public void Authenticate(IUser user)
    {
        // do some stuff here
    }
}

You can now instantiate and mock without having to specify the generic that will probably always be the same.

var repository = new UserRepository();
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top