Наследование интерфейсов в С#

Я пытаюсь перехватить довольно большую (для меня) проблему, с которой мне приходилось сталкиваться при написании моего приложения. Посмотрите на это, пожалуйста (я попытаюсь сократить код для простоты):

У меня есть интерфейс root IRepository<T>. Затем IBookRepository : IRepository<Book> Далее, конкретный класс, который его реализует: BookRepository : IBookRepository

В классе RepositoryManager я объявил private IRepository<IRepoItem> currentRepo;

IRepoItem - это интерфейс, реализуемый классом Book.

Теперь, когда я пытаюсь сделать что-то вроде этого:

currentRepo = new BookRepository();

VisualStudio дает сообщение об ошибке:

Невозможно неявно преобразовать тип 'BookRepository' в 'IRepository'. Явное преобразование существует (вы пропускаете листинг?)

Я попытался выполнить явно, но исключение времени выполнения выбрано...

Я знаю (почти наверняка), что это что-то называется ковариацией, и это (возможно) решено в .Net 4.0. К сожалению, я пишу, используя фреймворк версии 3.5, и я не могу это изменить. Пожалуйста, дайте мне несколько советов, что делать - как преодолеть эту проблему? Я хотел бы получить currentRepo из RepoFactory, который будет производить несколько видов репозиториев, зависит от потребностей пользователей. Я не знаю, разрешены ли ссылки здесь, но я пишу какой-то блог на http://olgatherer.wordpress.com/, где описываю создание приложения. Мой английский плохой, но я надеюсь, что этого достаточно, чтобы понять меня. Заранее благодарю вас за ответ.

С уважением, skrzeczowas

Ответ 1

В .NET 3.5 вы определенно не можете рассматривать IRepository<Book> как IRepository<IRepoItem>.

Нам нужно узнать больше о том, что вы используете репозиторий в RepositoryManager, чтобы действительно знать, как его решить... но вы могли бы создать не общий интерфейс IRepository, который IRepository<T> расширяет? Включите все элементы, которые не относятся к T. Тогда вы можете объявить currentRepo как только IRepository.

Ответ 2

Попробуйте использовать промежуточный уровень (IRep):

    interface IRepository<T>
    {
    }

    interface IRep<T> : IRepository<IRepoItem> where T : IRepoItem
    {
    }

    interface IBookRepository : IRep<Book>
    {
    }

    class BookRepository : IBookRepository
    {
    }

то вы можете делать то, что хотите:

        BookRepository br = new BookRepository();
        IRepository<IRepoItem> currentRepo = br;

Ответ 3

В .NET 3.5 нет никакой связи между IRepository и IRepository в .NET 4, вы могли бы достичь чего-то подобного с поддержкой ковариации и контравариантности (но это зависит от декларации интерфейса IRepository)

A будет рекомендовать использовать не общий интерфейс IRepository и делать бросок самостоятельно. Я знаю, это не чудесно, но описание, которое вы описываете, требует поддержки ковариации/контравариантности.