2

I don't know how manage properly the interfaces in C#. My goal is to have an abstract class for my Business Layer Services that have some common methods (like Save(), Dispose()), that call different DAL repository methods. I wish to avoid to repeat in all my services something like:

public Save() 
{
   repository.Save();
}

I have a scenario similar to that:

Interface

namespace Common
{
    public interface IRepository
    {
        void Save;
        void Dispose;
    }
}

DAL

namespace DAL
{
    public Repository : IRepository
    {
        public void Save() {};
        public void Dispose() {};
        public void Add() {}
    }
}

BL

namespace BL
{
    public abstrac BaseService
    {
        protected IRepository repository;
        protected BaseService(IRepository repo)
        {
            repository = repo;
        }

        public Save() 
        {
            repository.Save();
        }
    }

    //...

    //Tentative 1
    public Service : BaseService
    {
        private Repository rep;

        public Service()
            : base(new DAL.Repository())
        {
            rep = base.repository; // ERROR: cannot convert IRepository to Repository
        }
    }
}

I tried also this:

//Tentative 2
public Service : BaseService
{
    private IRepository rep;

    public Service()
        : base(new DAL.Repository())
    {
        rep = base.repository; // OK
    }

    public void Add()
    {
        rep.Add() // ERROR: IRepository doesn't contain a definition for 'Add'
    }
}

I know I could define in the interface all the methods I want to use, but I'll will have to manage a lot of problems with generic types and, as you should have understand from my question, I'm quite new in C# and I wish to avoid complexity is is possible, utill I'll be more expert at least :)

Davide
  • 1,305
  • 3
  • 16
  • 36
  • Because (I updated the post just now) I want to wrap in the base class some commons method that are basically the same (Save()) but with a reference to different DAL Repositories .. hope you can understand me .. I have problem with both C# and English languages ;) – Davide Jan 31 '13 at 10:15

3 Answers3

3

Firstly I think you're having a name clash with you member IRepository rep.

Try using DAL.IRepository rep

The reason that you're getting an error is that you've defined "Add" as something unique to "Repository". Your member variable is an "IRepository" allowing you to put anything that implements "IRepository" onto it.

Just because you CAN put a Repository into it, doesn't mean that everything on it is going to be a repository. (Think of it look good 'ol fingers and thumbs, all thumbs are fingers, but not all fingers are thumbs)

If you NEED to call add on any repository, then add it to the interface. Else, you need to decide whether or not that member should be IRepository or Repository.

Alternatively, you COULD use

    Repository myRep = rep as Repository;
    if(rep!=null)
    {
       myRep.Add();
       ...
       profit();
    }
Immortal Blue
  • 1,691
  • 13
  • 27
1
public Service()
        : base(new DAL.Repository())
    {
           rep = (Repository)base.repository;

    }

This way u will get the Add() service which is not a part of IRepository but a newer implementation in the extended class.

Raghavan
  • 637
  • 3
  • 12
  • I'm ashamed of my question .. it was so easy! probably I made the wrong question to google .. thank you very much – Davide Jan 31 '13 at 10:19
  • 1
    The answer fixes your problem (although no exception handling - could use `as` or `is` to check if your passed in IRepository is a Repository), but it's kind of breaking what I think you're trying to do with injecting an interface in the first place. You would probably be better either adding 'Add' to IRepository, or possibly rethinking your design. – Cashley Jan 31 '13 at 10:22
  • Well there is nothing 2 b ashamed of, u r on the right path. except i wudnt do it the casting way. i think u will understand when u make more repositories. right now since u just have one implementation of IRepository everything seems ok. When u implement the IRepository 4-5 times u will see the error of this design. – Raghavan Jan 31 '13 at 10:23
  • Exactly what the previous post said. u would have to do the check typeof(obj) = "Repository" before u call the add method because it is a newer implementation and will not be available to other implementations. but i dont think about it as a design flaw. it is just something we all have to decide after multiple classes have been designed, it is a little early to infer anything. – Raghavan Jan 31 '13 at 10:26
  • Thank you .. I was thinking the this design is a bit weird too .. if I understood correctly an iterface should provide the sign for commom behaviour (so Add IS common to all the derived class I'll create). And I'll try to change the design. Actully the problem is that the Add method takes different types of entities like argument, and I should create a generic interface to handle that .. I tried but is quite complicated for me at the moment .. but I'll do it as soon as my knowleadge will grow – Davide Jan 31 '13 at 10:53
  • 1
    ya absolutely Save and Dispose suffice and is the minimum binding implementation required. if u put in an Add in the IRepository then all the other implementations have to implement Add which is not what u want. Honestly u might have a DeleteRepository, CloneRepository, MultiplyRepository, GrowRepository which will not need to have an add but they all need to implement Save and Dispose.. so u will have to do typeof(IRepository) = "AddRepository" call Add, typeof(IRepository ob) = "CloneRepository" call Clone, typeof(IRepository obj) = "DeleteRepository" call Delete.. outside the Impl. – Raghavan Jan 31 '13 at 11:04
0

Seeing as your main problem is the lack of accessibility to the Add method, and seeing as this is a relative common method anyway, I would firstly recommend adding it to your IRepository, so it looks like this:

public interface IRepository
{
    void Add();
    void Save();
    void Dispose();
}

You would then implement your appropriate repositories whilst inheriting from IRepository. Now, understandably you may want to be able to access custom methods on a Repository. In order to resolve this what you could do is have your BaseService accept a generic repository:

public BaseService<T> where T : IRepository
{
    protected T repository { get; set; }
    protected BaseService(T repo)
    {
        repository = repo;
    }
}

Then a service would look like this

public UserService : BaseService<UserRepository>
{
    public UserService() : base(new DAL.UserRepository())
    {
        // base.Repository is now a UserRepository.
    }    
}

With this implementation your UserService will be able to access all of the methods that UserRepository exposes, as it's strongly typed with the generic. Hope this helps.

Richard
  • 8,110
  • 3
  • 36
  • 59