2010-10-06 29 views
10

Próbuję opanować dość duży (dla mnie) problem, który napotkałem podczas pisania mojej aplikacji. Spójrz na to, proszę (postaram się skrócić kod dla uproszczenia):Dziedziczenie dziedziczenia w C#

Mam interfejs root o nazwie IRepository<T>. Następnie IBookRepository : IRepository<Book> Następnie beton klasy, która implementuje go: BookRepository : IBookRepository

W klasie RepositoryManager oświadczyłem private IRepository<IRepoItem> currentRepo;

IRepoItem jest interfejs, który jest realizowany przez klasy Book.

Teraz, gdy próbuję zrobić coś takiego:

currentRepo = new BookRepository(); 

VisualStudio daje komunikat o błędzie:

nie można niejawnie przekonwertować typu 'BookRepository' do 'IRepository'. Wyraźne konwersji istnieje (czy brakuje obsady?)

Próbowałem rzucić jawnie, ale wyjątek środowiska wykonawczego jest wyrzucany ...

wiem (prawie na pewno), że jest to coś, co nazywa kowariancji i jest to (prawdopodobnie) rozwiązane w .Net 4.0. Niestety piszę przy użyciu wersji ramowej 3.5 i nie mogę tego zmienić. Proszę dać mi kilka rad, co robić - jak pokonać ten problem? Chciałbym, aby currentRepo z RepoFactory, który produkuje kilka rodzajów repozytoriów, zależy od potrzeb użytkownika. Nie wiem, czy linki są tutaj dozwolone, ale piszę coś w rodzaju bloga pod numerem http://olgatherer.wordpress.com/, gdzie opisuję tworzenie aplikacji. Mój angielski nie jest dobry, ale mam nadzieję, że wystarczy mnie zrozumieć. Z góry dziękuję za odpowiedź.

poważaniem, skrzeczowas

+0

Co jest zadeklarowany typ currentRepo? –

+0

Nieważne, widzę, że jest to IRepository . –

Odpowiedz

4

W .NET 3.5 na pewno nie można traktować jako IRepository<IRepoItem>IRepository<Book>.

Chcemy wiedzieć więcej o tym, co używasz repozytorium w RepositoryManager naprawdę wie, jak go rozwiązać ... ale można utworzyć nierodzajową IRepository interfejs, który IRepository<T> rozciąga? Niech to będzie zawierało wszystkich członków, którzy nie odnoszą się do T. Wtedy możesz zadeklarować currentRepo jako tylko IRepository.

+0

+1 - Myślałem o tym nie generycznym interfejsie 'IRepository', ale nie byłem pewien, jak go przynieść. Doskonały Jon! =) –

+0

Cześć jeszcze raz! Mam repozytoria w sposób opisany tutaj: http://olgatherer.wordpress.com/2010/08/18/repositoriesrus/ I stworzyłem DbManager do zarządzania bazą danych i tworzenia repozytoriów dla każdego z tabel (książek, komiksów, poststampów, itd.). Teraz chciałbym, aby currentRepository w DbManager mogło być BookRepository, StampsRepository, cokolwiek - myślałem, że to coś z interfejsami byłoby OK, ale niestety nie jest, ponieważ IRepoItem (jak zdawałem sobie sprawę dzisiaj) powinien mieć wszystkie różne właściwości wtedy ... :( – skrzeczowas

0

W .NET 3.5 nie ma żadnych relacji między IRepository i IRepository w .NET 4, można osiągnąć coś podobnego z kowariancji i kontrawariancji wsparcia (ale to zależy od deklaracji interfejsu IRepository)

niedoszły zalecamy używanie nietypowego interfejsu IRepository i samodzielne wykonywanie rzutów. Wiem, to nie jest cudowne, ale opisywana fonctionalność wymaga wsparcia kowariancji/kontrawariancji.

+0

Dziękuję za tę odpowiedź, użyłem tego poniżej i zdałem sobie sprawę, że to nie w pełni mi odpowiada :(Nie wiem co teraz zrobić ... IRepoItem nie mógł mieć wszystkich właściwości, które książki, komiksy, znaczki składają się z :( – skrzeczowas

1

Spróbuj użyć warstwę pośrednią (IREP):

interface IRepository<T> 
    { 
    } 

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

    interface IBookRepository : IRep<Book> 
    { 
    } 

    class BookRepository : IBookRepository 
    { 
    } 

potem możesz robić, co chcesz:

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

Cześć! To jest wspaniałe i bardzo eleganckie, bardzo się cieszę, że to napisałeś. Niestety, jak opisałem w komentarzu do powyższego posta, zdałem sobie sprawę, że to nie w pełni mi odpowiada. IRepoItem jest Interfejs, który byłby zaimplementowany w książkach, znaczkach, komiksach, a więc miałby wszystkie właściwości dla różnych elementów.Nie jest to inteligentne i muszę znaleźć inny sposób osiągnięcia tego, co chcę - to znaczy, że chcę, żeby currentRepo było BookRepository lub StampsRepository lub jakiekolwiek inne repozytorium ... Może jakaś pomoc, proszę? – skrzeczowas

+0

IRepoItem, będący interfejsem dla innych rzeczy, powinien tylko spowodować konsolidację wspólnych elementów, a nie "wszystkich właściwości". Na przykład, IMoveable powinno ujawniać tylko metodę Move, a nie każdą rzecz, którą posiadają wszystkie klasy (takie jak Cheetah, Car, Airplane). – Grozz

+0

Ale jeśli, powiedzmy, będę miał currentRepo = StampsRepo() ;, będę mógł używać tylko tych metod, z których składa się IRepository. Nie będę mógł używać metod IStampsRepository :(Wierzę, że mogę wtedy zapytać, jaki typ jest ten currentRepo: jeśli (currentRepo jest IBookRepository) zrób coś innego, jeśli (currentRepo jest IStampsRepository) zrób coś ... Ale to nie jest Dobre programowanie obiektowe, myślę, że muszę przemyśleć wszystkie założenia, które zrobiłem, bo może to, czego chcę, jest głupie i niemożliwe do osiągnięcia ... – skrzeczowas