2012-04-18 15 views
5

aby uniknąć nieporozumień podsumowałem jakiś kod:Jak zaimplementować rodzajowy polimorfizm w języku C#?

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main() 
     { 
      IManager<ISpecificEntity> specificManager = new SpecificEntityManager(); 
      IManager<IIdentifier> manager = (IManager<IIdentifier>) specificManager; 
      manager.DoStuffWith(new SpecificEntity()); 
     } 
    } 

    internal interface IIdentifier 
    { 
    } 

    internal interface ISpecificEntity : IIdentifier 
    { 
    } 

    internal class SpecificEntity : ISpecificEntity 
    { 
    } 

    internal interface IManager<TIdentifier> where TIdentifier : IIdentifier 
    { 
     void DoStuffWith(TIdentifier entity); 
    } 

    internal class SpecificEntityManager : IManager<ISpecificEntity> 
    { 
     public void DoStuffWith(ISpecificEntity specificEntity) 
     { 
     } 
    } 
} 

Kiedy debugowania kodu otrzymuję InvalidCastException w Main().

Wiem, że ISpecificEntity implementuje . Ale oczywiście bezpośrednia obsada od IManager<ISpecificEntity> do IManager<IIdentifier> nie działa.

Myślałem, że praca z kowariancją może załatwić sprawę, ale zmiana IManager<TIdentifier> na IManager<in TIdentifier> również nie pomaga.

Czy istnieje sposób na przeniesienie specificManager do IManager<IIdentifier>?

Dzięki i wszystkim, co najlepsze.

+0

proszę przeczytać: http://stackoverflow.com/questions/245607/how-is-generic-covariance-contra-variance-implemented-in-c-sharp-4-0 –

Odpowiedz

7

Z IManager<IIdentifier> można zrobić coś takiego:

IIdentifier entity = new NotSpecificEntity(); 
manager.DoStuffWith(entity); 

który doprowadzi do wyjątku w swojej SpecificEntityManager, ponieważ akceptuje tylko parametry typu ISpecificEntity

UPDATE: Możesz przeczytać więcej o kowariancji i kontrawariancja w języku C# pod numerem Eric Lippert's blog

+0

... i dlatego to nie jest nie wolno robić tego, co chce zrobić OP. +1 –

+0

@DanielHilgarth dokładnie :) –

+0

Ale 'ISpecificEntity' implementuje' IIdentifier'. Natomiast 'TIdentifier' w' IManager' akceptuje tylko 'IIdentifier'. Tak więc nie powinno być wyjątku w tej linii. Czy się mylę? – Palama

2

Dlaczego nie:

ISpecificEntity bankAccountManager = new SpecificEntity(); 
IManager<IIdentifier> manager = (IManager<IIdentifier>)bankAccountManager; 
manager.DoStuffWith(new SpecificEntity()); 

?

+0

Ponieważ "SpecificEntity" nie jest "IManager ", ale "IIdentifier". – Palama