2017-02-08 5 views
2

Чтобы использовать инъекцию зависимостей в .NET Core, мы создали связку интерфейсов репозитория для наших контроллеров, используемых для взаимодействия с базами данных.Интерфейсы и наследование с помощью дженериков в C#

У нас есть класс EntityBase, в котором есть некоторые методы, а наш общий интерфейс репозитория использует этот базовый класс: IRepository<T> where T : EntityBase.

Я хочу добавить более конкретный класс TaggedEntityBase, который расширяет EntityBase, чтобы представить тот факт, что у нас есть некоторые объекты, которые мы хотим фильтровать по тегам. Я хочу, чтобы TaggedEntityBase имел абстрактное свойство, которое я могу использовать в своем контроллере, чтобы я мог абстрагироваться и повторно использовать метод фильтрации.

Так что я хочу что-то вроде этого, но я думаю, что я хочу ITaggedRepository также наследовать от IRepository так, чтобы класс, реализующий ITaggedRepository гарантированно иметь метод ListAll и ListWithTags метод:

public class EntityBase { } 

public abstract class TaggedEntityBase : EntityBase 
{ 
    public string TagIDs { get; } 
} 


public interface IRepository<T> where T : EntityBase 
{ 
    IEnumerable<T> ListAll(); 
} 

public interface ITaggedRepository<T> where T : TaggedEntityBase 
{ 
    IEnumerable<T> ListWithTags(System.Linq.Expressions.Expression<Func<T, bool>> predicate); 
} 

I «Я уверен, что я просто полностью смутил себя, преследуя эту линию мышления, но я не уверен, как делать то, что я действительно хочу здесь. Я знаю, что мне нужно сохранять абстракцию для инъекций зависимостей, но я чувствую, что я нахожусь на грани того, что возможно с интерфейсами.

Есть ли лучшая линия мышления, которая заставит меня туда, куда я пытаюсь идти?

+2

Не 'ITaggedRepository : IRepository ' делать то, что вы хотите , или я что-то упустил в вашем вопросе? – CodeCaster

+0

Я хочу ограничить 'ITaggedRepository', чтобы потребовать' TaggedEntityBase' –

+0

Вы можете, becasuse 'TaggedEntityBase: EntityBase'. – CodeCaster

ответ

3

Вы можете пойти дальше и наследовать от IRepository<T>:

public interface ITaggedRepository<T> : IRepository<T> where T : TaggedEntityBase 
{ 
    IEnumerable<T> ListWithTags(Expression<Func<T, bool>> predicate); 
} 
+0

Я получаю эту ошибку, когда я это делаю: 'Тип 'T 'не может использоваться как параметр типа' T 'в родовом типе или методе' IRepository '. Нет никакого неявного преобразования ссылок из 'T' в 'EntityBase'. ' –

+0

Вы включили 'where T: TaggedEntityBase'? –

+0

Да. То, что у вас есть, - это именно то, что у меня есть в моем коде, и эта ошибка заставляет меня прийти сюда смущенно без конца. –

2

В какой-то момент вы можете в неприятности, если ваш TaggedEntity это на самом деле не абстракция. Скажем, у вас также есть NamedEntities, а некоторые - с тегами.

Теперь у вас есть INamedRepository, ITaggedRepository и INamedTaggedRepository (вы столкнетесь с аналогичными проблемами на своей базовой сущности).

Вы могли бы сделать больше черты, как вещи, как:

public class EntityBase {} 

public interface ITagged 
{ 
    string TagIDs { get; } 
} 

public interface INamed 
{ 
    string Name { get; } 
} 

public class Book : EntityBase, ITagged, INamed 
{ 
    public string TagIDs { get; set; } 
    public string Name { get; } 
} 

public interface IRepository<T> where T : EntityBase 
{ 
    IEnumerable<T> ListAll(); 
} 

public interface IQueryTags<T> where T : ITagged 
{ 
    IEnumerable<T> ListWithTags(Expression<Func<T, bool>> predicate); 
} 

public interface IQueryByName<T> where T : INamed 
{ 
    T GetByName(string name); 
} 

public interface IBookRepository : IRepository<Book>, IQueryTags<Book>, IQueryByName<Book> 
{ 

} 

public class ConcreteBookRepository: IBookRepository 
{ 
    public IEnumerable<Book> ListAll() 
    { 
     throw new NotImplementedException(); 
    } 

    public IEnumerable<Book> ListWithTags(Expression<Func<Book, bool>> predicate) 
    { 
     throw new NotImplementedException(); 
    } 

    public Book GetByName(string name) 
    { 
     throw new NotImplementedException(); 
    } 
} 

В конкретной реализации вы могли бы, по составу, использовать ByNameQueryer, TagQueryer и некоторые конкретное Repository.

Мне не нравятся общие хранилища, поэтому я склонен переименовывать IRepository в IStore, так как обычно он обычно содержит только CRUD-аспект.

О, а затем некоторые объекты, которые вы не можете удалить, некоторые не могут быть обновлены. Вы будете в конечном итоге разрыв, что вплоть до IAdd, IUpdate, IDelete и т.д. Это где вы начинаете задаваться вопросом, было ли это на самом деле хорошая идея также ;-)

 Смежные вопросы

  • Нет связанных вопросов^_^