Метод расширения, который возвращает правильную реализацию интерфейса? - PullRequest
4 голосов
/ 27 октября 2011

Я не уверен, возможно ли это, и мне может понадобиться написать методы расширения для каждой реализации.Вот пример кода:

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;
     }
}

Итак, допустим, я использую UserService.Когда я вызываю метод расширения в UserService, можно ли заставить его возвращать правильную реализацию IBaseService или мне нужно создать метод расширения для каждой реализации?:

Пример:

userService.EnableLazyLoading(false).FindByUsernameAndPassword("ddivita","123456")

Ответы [ 2 ]

3 голосов
/ 27 октября 2011

Вы можете сделать это следующим образом:

public static S EnableLazyLoading<T, S>(this S service, bool lazyLoad = true)
     where S : IBaseService<T>
{
     service.UnitOfWork.EnableLazyLoad(lazyLoad);
     return service;
}
2 голосов
/ 27 октября 2011

Хорошо, это может работать, а может и не работать с вашим дизайном, но оно основано на ответе Феликса (за что он должен получить кредит) и делает его выводимым.

Поскольку ваш класс UnitOfWork делаетне зависит от типа T, вы можете создать IBaseService, который не является универсальным, который содержит член UnitOfWork, а затем сделать IBaseService<T> extension IBaseService примерно так:

public interface IBaseService
{
    // all non-type-T related stuff
    IUnitOfwork UnitOfWork {get;}
}

public interface IBaseService<T> : IBaseService
{
    // .. all type T releated stuff
}

Затем,сохраняйте остальную часть дизайна вашего класса как обычно и напишите метод расширения следующим образом:

public static S EnableLazyLoading<S>(this S service, bool lazyLoad = true)
     where S : IBaseService
{
     service.UnitOfWork.EnableLazyLoad(lazyLoad);
     return service;
}

Поскольку нам не нужно IBaseService<T>, чтобы получить UnitOfWork сейчас, нам не нужно указывать второйпараметр типа T, который делал вывод проблематичным.Так что теперь мы можем написать код точно так, как вы хотели, потому что теперь он может вывести S is UserService без необходимости знать о типе T (User):

userService.EnableLazyLoading(false).FindByUsernameAndPassword("ddivita","123456");

Конечно, это предполагает, как я уже сказал, что UnitOfWork ничего не нужно от типа T.

Как я уже сказал, @Felix заслуживает ответа, но просто хотел бы расширить, как можно сделать этоВыводит возможность избежать передачи параметра универсального типа.Голоса приветствуются, хотя: -)

...