Reputation: 145
I have an application that is structured as an service layer wich uses a repository layer for persistence. I'm trying to create a generic controller class to reuse shared behavior but I'm having trouble trying to set the generic parameters. The following code:
public class BusinessEntity
{ }
public class Person : BusinessEntity
{ }
public interface IRepository<T> where T : BusinessEntity
{ }
public interface IService<T, R>
where T : BusinessEntity
where R : IRepository<T>
{ }
public partial interface IPersonRepository : IRepository<Person>
{ }
public interface IPersonService : IService<Person, IPersonRepository>
{ }
public abstract class BaseController<X, Y>
where X : BusinessEntity
where Y : IService<X, IRepository<X>>
{ }
public class PersonController : BaseController<Person, IPersonService>
{ }
fails at compilation with
The type ConsoleApplication.IPersonService
cannot be used as type parameter Y
in the generic type or method ConsoleApplication.BaseController<X,Y>
. There is no implicit reference conversion from ConsoleApplication.IPersonService
to ConsoleApplication.IService<ConsoleApplication.Person,ConsoleApplication.IRepository<ConsoleApplication.Person>>
this works
public interface IPersonService : IService<Person, IRepository<Person>>
but I lose the custom repository
There is a way to make the compiler realize IPersonRepository
is an IRepository<Person>
?
Upvotes: 3
Views: 759
Reputation: 43076
public class BusinessEntity
{ }
public class Person : BusinessEntity
{ }
public interface IRepository<T> where T : BusinessEntity
{ }
public interface IService<T, R>
where T : BusinessEntity
where R : IRepository<T>
{ }
public partial interface IPersonRepository : IRepository<Person>
{ }
public interface IPersonService : IService<Person, IPersonRepository>
{ }
public abstract class BaseController<X, Y, Z>
where X : BusinessEntity
where Y : IService<X, Z>
where Z : IRepository<X>
{ }
public class PersonController : BaseController<Person, IPersonService, IPersonRepository>
{ }
To address your comment:
IPersonService can extend the base service class to add custom facilities, like FindPersonsUnderAge(). For this it requires a custom repository. Actually LINQ avoids a lot of custom repository code, but sometimes they are required.
Couldn't IPersonService do that without requiring the repository type to be a type parameter? For example:
public interface IService<T> where T : BusinessEntity { }
public interface IPersonService : IService<Person>
{
IEnumerable<Person> FindPersonsByAge(double minAge, double maxAge);
}
public class Service<T, R> : IService<T>
where T : BusinessEntity
where R : IRepository<T>
{ }
public class PersonService : Service<Person, IPersonRepository>, IPersonService
{ }
Upvotes: 4
Reputation: 145
Thanks to sll for pointing me in the right direction
public interface IService<T, out R>
where T : BusinessEntity
where R : IRepository<T>
{ }
does the trick
Upvotes: 0