Search code examples
c#interfacedependency-injectionloose-coupling

interfaces and dependency injection correct use in C#


I have an interface "IUser" and a class "User" implementing "IUser". Also I have an interface for the repository "IUserRepository".

I'm between these two options:

public interface IUserRepository
{
    List<User> getAll();
    void addUser(User user);
    void alterUser(User user);
    void deleteUser(string ID);
    bool validateLogin(string session_user, string session_pass);
    User getUserByID(int ID);
    User getUserByNombre(string name);
    User getUserBySessionUser(string session_user);
}

and this

public interface IUserRepository
{
    List<IUser> getAll();
    void addUser(IUser user);
    void alterUser(IUser user);
    void deleteUser(string ID);
    bool validateLogin(string session_user, string session_pass);
    IUser getUserByID(int ID);
    IUser getUserByNombre(string name);
    IUser getUserBySessionUser(string session_user);
}

Here is my confusion. Should my methods in the repository interface return real implementations or interfaces? as you can see in my first option I'm returning "User" instances. What I should return to loosely couple the code?

But if I choose the second one in my real implementation of the user repository I will only have access to the methods and properties that I had declared in my IUser interface.

for example if I call addUser method from a service passing it an instance of User class:

   myRepositoryImplementation.addUser(UserInstance);

then my real repository is going to like this

  private readonly IUser user;
  public void addUser(IUser _user)
  {
    this.user=_user;
  }

Nice valid catch! but then I will only have access to the method and properties declared initially in the IUser interface and not of any new method or property declared in my User instance.

also if I call getUserByID method I will receive an IUser instance.

So to resume this

1). Are these valid approaches?
2). If these are valid approaches which one should I use to preserve or keep the code decoupled?
3). If I choose the second one also if it is valid then should I declare in the interface all I'm going to use later? I mean properties and methods?
3). Have a better idea?


Solution

  • 1) yes, both are valid

    3) yes, properties and methods

    2) a little longer story. in short, if you have POCO classes and you are 100% sure you are never going to code against a framework that doesn't allow you to use POCOs (e.g. instead, it insists on classes inheriting from a framework-specific base class), you could go with the first option (classes).

    But it not always works.

    For example, coding your repositories for Linq2SQL and other repositories for Entity Framework Code First, you can't use the very same set of classes. The second (interface) approach is the only option. We've succesfully used it in several enterprise applications with no issues.

    A word of advice - if you go with the interface approach, you definitely need a method to create an empty instance

    public interface IUserRepository
    {
        List<IUser> getAll();
        ...
        IUser CreateNew();
    }
    

    Otherwise the repository client has no other means of creating an instance of a concrete type - the type is unknown to the client. Some people tend to move the creation method to a separate factory class, though.