1

Normally we have some code that is common for many (if not all) derived classes. An example would be a generic repository (where I could have a generic Add, Remove, Count, Max, Load etc, or a generic model (example, a common business rule to get a unique value for a new entity based on property type, or a generic save method, etc).

Now, if I were to make a Generic model that accepts Generic repository, it could look ilke:

GenericModel<TEntity> : IGenericModel<TEntity>
{
    internal GenericModel(IRepository<TEntity> genericRepository)
    {

    }
    protected IRepository<TEntity> Repository {get; }
}

Now I need a specific model with a specific repository:

class ActivityModel : GenericModel<Activity>
{
    protected ActivityModel(IActivityRepository activityRepository)
}

where

class ActivityRepository : GenericRepository<Activity>, IActivityRepository { }

That means that in ActivityModel I need to cast Repository property to IActivityRepository anytime I need to use IActivityRepository specific methods, or I can declare a new property in ActivityModel

private new IActivityRepository Repository {get { return base.Repository; } }

to hide the base.Repository property, but I am not sure whether I am doing something wrong by using this approach.

Another approach would be to add another generic paramteter

class GenericModel<TEntity, TRepository> where TRepository : IRepository<TEntity>

but I am not sure if this is also a correct approach.

So any thoughts on how to handle generic and specific implementations?

  • 3
    Why do you want the model to be aware of the repository? – Theraot Jul 16 '18 at 11:11
  • @Theraot You got me confused here. How can a model get the data then, if not using IRepository interface? Something needs to provide data to model, and model needs to be aware of that thing. Whould you like to clarify your statement a bit? – Goran Jul 17 '18 at 14:20
  • I agree I could have elaborated more. I am not arguing IRepostory, however it being exposed in model, and having specific interfaces makes wonder what is the intent. If you want the model to use the repository, then it is a dependency, and probably not one you want to expose. Ok, you have your reasons... I see no problem in having a more specific type as constructor parameter to inject the dependency. However, adding it to the model interface brings trouble. Aside from that... No, the model does not need to know from where the data comes from. – Theraot Jul 17 '18 at 16:35
  • @Theraot IRepository is a dependency, and is injected in constructor. I am exposing it only for descendent types (its protected), it is not part of the model interface. Model does not know how repository gets the data, it just invokes the requird methods. The problem is that base class can do (and does) common jobs with IRepository, but super class needs to have a specific repository to use specific methods. This is were my problem with constantly casting IRepository to specific repository. And this is why I asked if it is normal behavior or not.. – Goran Jul 25 '18 at 8:56
2

It's a general aspect of inheritance that you can't remove stuff.

In your specific example you could just ignore the protected repository, but it would potentially break further inheritance, or at least confuse it.

A simple solution would be just not to inherit from GenericModel at all, but I suppose we can assume GenericModel has some other public functionality that you do want to use.

The general answer is to: 'Prefer composition over inheritance', avoid the GenericModel completely and have a private IRepository where required. Then you can simply switch out to a specific repository in classes that use it.

eg:

public class ActivityModel : IGenericFunctionality
{
    public ActivityModel(
        IActivityRepository activityRepository,
        IGenericFunctionalityProvider gfp
    )
    {
        this.gfp = gfp;
        this.activityRepository = activityRepository;
    }

    public void GenericFunctionality() 
    {
        this.gfp.GenericFunctionality();
    }
}
  • I do not understant the benefit of such approach. My understanding is that composition is used when something is not requiring all functionality from anotehr super class, so composition is required to hide all that uncecessary functionality. In my case, IActivityRepository needs all the methods from IRepository, so why would I need to use composition? Does it mean that, in case where I inject an inteface of some base tope, and then I need to have another super class, with injected inteface of another super class, in that case I never use inheritance? – Goran Jul 17 '18 at 14:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.