Search code examples
c#.netoopdependency-injectioninterface

How to pass a class in interface definition


I create BaseService with common functions for all entities which inherit the base object, public class Committee : BaseObject:

public interface IBaseService<T> where T : BaseObject
{
}

public class BaseService<T> : IBaseService<T> where T : BaseObject
{
}

injection:

services.AddScoped(typeof(IBaseService<>), typeof(BaseService<>));

then I use it like this:

readonly IBaseService<Committee> _committeeService;

But for some entities, which also inherits the base object public class Evaluation : BaseObject, I need a service, for each, with some extra business logic. So, I create a specific service which inherits base service:

public interface IEvaluationService<T> : IBaseService<T> where T : Evaluation
{
}

public class EvaluationService<T> : BaseService<Evaluation>, IEvaluationService<Evaluation>
{
}

injection:

services.AddScoped(typeof(IEvaluationService<>), typeof(EvaluationService<>));

and usage is like this:

readonly IEvaluationService<Evaluation> _evaluationService;

This code works just fine. But I'm wondering, why I have to pass <Evaluation> when I use IEvaluationService<Evaluation>. Why cannot I use it just like this:

readonly IEvaluationService _evaluationService;

???

The entity Evaluation is already passed in the IEvaluationService definition. Why do I need to pass it again in usage?

Is there a way to simplify the usage of this service to be just readonly IEvaluationService _evaluationService;?


Solution

  • The interface is declared with a type parameter T:

    public interface IEvaluationService<T> : IBaseService<T> where T : Evaluation
    {
    }
    

    That type parameter is not optional. While the T is constrained to Evaluation, this only means that T may be Evaluation or any subtype of Evaluation.

    While IEvaluationService<Evaluation> is certainly valid, so would IEvaluationService<SubEvaluation> be, if SubEvaluation : Evaluation.

    Thus, when you've declared the interface like that, you have to state which T you're interested in.

    If you only ever want to support Evaluation, and no subtypes of it, you could have declared the interface like this:

    public interface IEvaluationService : IBaseService<Evaluation>
    {
        // More members here..?
    }
    

    That would enable you to use it as IEvaluationService, because that type has no open generics.