Наследование интерфейсов в С#
Я пытаюсь перехватить довольно большую (для меня) проблему, с которой мне приходилось сталкиваться при написании моего приложения.
Посмотрите на это, пожалуйста (я попытаюсь сократить код для простоты):
У меня есть интерфейс 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 и делать бросок самостоятельно. Я знаю, это не чудесно, но описание, которое вы описываете, требует поддержки ковариации/контравариантности.