Как указать на общий абстрактный класс? - PullRequest
1 голос
/ 19 ноября 2010

У меня нет проблем с кодом со времени моей последней проблемы с ковариацией интерфейса.Сегодня я принял другой подход к архитектуре OLGAtherer, и я нашел огромное (для меня) препятствие.Я надеюсь, что это огромный только для меня, и я найду ответ здесь :) Хорошо, пожалуйста, проверьте это:

У меня есть абстрактный универсальный класс:

abstract class Repository<T> where T : Entity

этот класс содержит подписи четырехМетоды CRUD (добавить, вставить и т. Д.) И два защищенных поля.Любой репозиторий, который я создам, должен наследоваться от этого суперкласса.У меня есть репозитории, например:

class BookRepository : Repository<Book>

Теперь у меня есть класс DB, который отвечает за операции над файлом DB.И есть моя проблема.Посмотрите на этот метод, помещенный в класс БД:

    void Add(List<Entity> enitites, Type entityType)
    {
       Repository<entityType> repo = EntitiesFactory(entityType);
       repo.Add(entities);
    }

Я знаю, что вышеописанный метод не будет работать, но это визуализирует мою проблему (надеюсь) - я хотел бы динамически создать хранилище указанного типа, ноЯ понятия не имею, как это сделать.Это всегда было моей основной проблемой ООП - я мог кодировать наследование (или реализацию интерфейсов), но я не мог использовать эти унаследованные классы.Пожалуйста, объясните мне это.Заранее спасибо.

Paweł


Я использовал подсказки, которые вы предоставили, и вот что у меня сейчас:

public void Add<T>(List<T> entities, string repoName) where T : Entity
{
   Repository<T> repo = RepoFactory<T>(repoName, typeof(T));
   repo.Add(entities);
}

private Repository<T> RepoFactory<T>(string repoName, Type t) where T : Entity
{
   if (t == typeof(Book))
   {
   Repository<T> repo = (Repository<T>)((object)(new BookRepository(this.ConnectionString, repoName)));
   }

   return null;

}

RepoFactory теперь находится в классе БД (который, кстати, здесь является своего рода мостом) - его, вероятно, следует перенести в другое место, но здесь это не главная проблема.

Во-первых, я не знаю, правильно ли реализовано тело RepoFactory - наверное, нет.

Второе - я предполагаю, что буду вызывать методы БД из другого класса (скажем - WindowsForm, для простоты).Я буду называть Add с параметром T, зависящим от выбора пользователя.В этой ситуации у меня проблема и я ее временно исправляю, потому что теперь с БД все в порядке, но если мне придется реализовать код WindowsForm, я столкнусь с этим в другой раз (я думаю) - в будущем я постараюсь выяснить ответ на этот вопрос.тот же вопрос, но на более высоком уровне (выше БД) - я надеюсь, вы понимаете меня ... Я имею в виду, что я не буду знать, как динамически вызывать метод Add, потому что T будет зависеть от выбора пользователя (OLGAtherer долженбыть менеджером репозитория, который будет поддерживать Книги и другие виды коллекций).И если пользователь попытается работать со своей коллекцией книг, мне придется вызвать метод Add ().Если с коллекцией комиксов, добавить ().Я не хочу писать урок выше для каждого вида коллекций, но вместо этого используйте один вызов Add для этого.

Если вы понимаете, что я имею в виду, вы действительно хороши :) Мой английский отстой,но я работаю над этим.Спасибо за предыдущие ответы и заранее спасибо за дальнейшие.Paweł

Ответы [ 5 ]

7 голосов
/ 19 ноября 2010

Я не совсем уверен, что вы хотите.Подойдет ли это?

void Add<T>(List<T> entities) where T : Entity
{
   Repository<T> repo = EntitiesFactory(typeof(T));
   repo.Add(entities);
}

Кроме того, я предлагаю вам максимально гибко использовать входные параметры, например, используйте IEnumerable<T> вместо List<T> для этого метода, а также в методе Repository<T>.Add().Возможно, вы захотите передать лениво оцененный запрос или объединить несколько методов LINQ вместе.

3 голосов
/ 19 ноября 2010

Вы можете сделать метод Add универсальным.

void Add<T>(List<T> enitites)
{
   Repository<T> repo = EntitiesFactory(typeof(T));
   repo.Add(entities);
}
2 голосов
/ 19 ноября 2010

Просто для того, чтобы добавить ответы остальных, вы также можете взглянуть на шаблон проектирования Inversion of Control (IoC). Это может упростить вашу жизнь в будущей работе.

Благодаря внедрению зависимостей, которое дает вам IoC, вы можете значительно упростить, например, использование EntitiesFactory.

Я сейчас использую StructureMap для реализации IoC, и он хорошо работает для меня.

Вот страница Мартина Фаулера по IoC и из Википедии, чтобы вы могли начать.

2 голосов
/ 19 ноября 2010

Вы можете сделать его типобезопасным, изменив ваш объект в иерархии еще одним слоем косвенности следующим образом:

public abstract class EntityCollection<T> : List<T>
    where T : Entity
{
    public abstract Repository<T> GetRepository();
}

public class BookCollection : EntityCollection<Book>
{
    public override Repository<Book> GetRepository()
    {
        return BookRepository();
    }
}

Так что теперь вы можете изменить свой класс DB следующим образом:

public void Add<T>(EntityCollection<T> entities)
{
    Repository<T> repo = entities.GetRepository();
    repo.Add(entities);
}

Так что теперь вы можете передать экземпляр BookCollection в ваш Add метод, и он будет работать на 100% безопасным для типов, прозрачным способом.

1 голос
/ 20 ноября 2010

Все, что вы возвращаете в EntitiesFactory(), - это то, что вам нужно использовать.Так что проблема действительно в коде, который вы не показали.Покажите код для EntitiesFactory(), и мы получим лучшее представление о том, что вы пытаетесь выполнить.

ПРИМЕЧАНИЕ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...