Reputation: 4265
I am not sure if this is possible and I may need to write extension methods for each implementation. Here is some example code:
public interface IBaseService<T>
{
IUnitOfwork UnitOfWork {get;}
}
public interface IService<T>: IBaseService<T>
{
IEnumerable<T> GetAll();
T GetById(Guid id);
}
public interface IUserService: IService<User>
{
User FindByUsernameAndPassword(string username, string password)
}
public class BaseService<T>: IService<T>
{
public BaseService(IRepository<T> repository)
{
_repository = repository
}
public virtual IEnumerable<T> GetAll(){....};
public virtual T GetById(Guid id){....};
IUnitOfWork UnitOfWork {get {return _repository.UnitOfWork;}}
}
public class UserService: BaseService<User>, IUserService
{
...
}
public static class ServiceExtensions
{
public static IBaseService<T> EnableLazyLoading<T>(this IBaseService<T> service, bool lazyLoad = True)
{
service.UnitOfWork.EnableLazyLoad(lazyLoad);
return service;
}
}
So, let's say I am using the UserService. When I call the extension method on the UserService, is it possible to have it return the proper implementation of IBaseService or do I need to create and Extension Method for each implementation?:
Example:
userService.EnableLazyLoading(false).FindByUsernameAndPassword("ddivita","123456")
Upvotes: 4
Views: 239
Reputation: 38397
Okay, this may or may not work with your design, but it builds on Felix's answer (which he should get the credit for) and makes it infer-able.
Because your UnitOfWork
class does not depend on type T
, you can create an IBaseService
that is non generic that contains the UnitOfWork
member, then make IBaseService<T>
extend IBaseService
like so:
public interface IBaseService
{
// all non-type-T related stuff
IUnitOfwork UnitOfWork {get;}
}
public interface IBaseService<T> : IBaseService
{
// .. all type T releated stuff
}
Then, keep rest of your class design as normal and write the extension method as:
public static S EnableLazyLoading<S>(this S service, bool lazyLoad = true)
where S : IBaseService
{
service.UnitOfWork.EnableLazyLoad(lazyLoad);
return service;
}
Since we don't need the IBaseService<T>
to get UnitOfWork
now, we don't need to specify the second type parameter T
which was making inference problematic. So now we can write the code exactly as you wanted because it can now infer S
is UserService
without needing to know about the type T
(User
):
userService.EnableLazyLoading(false).FindByUsernameAndPassword("ddivita","123456");
Of course, this is assuming, as I said, that UnitOfWork
doesn't need anything from type T
.
As I said, @Felix deserves the answer, but just wanted to expand on how could make it infer-able to avoid having to pass in the generic type parameter. Up-votes are appreciated though :-)
Upvotes: 2
Reputation: 6281
You can do it this way:
public static S EnableLazyLoading<T, S>(this S service, bool lazyLoad = true)
where S : IBaseService<T>
{
service.UnitOfWork.EnableLazyLoad(lazyLoad);
return service;
}
Upvotes: 3