2013-01-09 12 views
59

Podczas rozmowy z kolegą o C#, pokazał mi kod C#, który musiałem przewidzieć wyjście. To wyglądało na proste, ale tak nie było. Nie mogę naprawdę zrozumieć, dlaczego C# działa w ten sposób.zrozumienie zagnieżdżonych klas generycznych w C# z quizem

Kod:

public class A<T1> 
{ 
    public T1 a; 

    public class B<T2> : A<T2> 
    { 
     public T1 b; 

     public class C<T3> : B<T3> 
     { 
      public T1 c; 
     } 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     A<int>.B<char>.C<bool> o = new A<int>.B<char>.C<bool>(); 

     Console.WriteLine(o.a.GetType()); 
     Console.WriteLine(o.b.GetType()); 
     Console.WriteLine(o.c.GetType()); 

     Console.ReadKey(); 
    } 
} 

Wyjście jest:

System.Boolean 
System.Char 
System.Int32 

Popraw mnie jeśli się mylę, ale rozumiem, że o.a jest typu bool ponieważ C<T3> dziedziczy od B<T3> i B<T2> dziedziczy od A<T2>. I mogę też nieco zrozumieć, że o.c jest typu int, ponieważ typ c jest T1, który pobiera z klasy zewnętrznej (myślę).

Moja głowa prawie eksploduje, gdy próbuję ustalić, dlaczego o.b jest typu char. Czy ktoś może mi to wyjaśnić?

+38

Cieszę się, że nie utrzymuję kodu w twojej firmie. – Default

+0

Interesujące, ale całkowite przesadzenie za cokolwiek praktycznego. Zakładam, że to akademickie, a nie do pracy? – JGilmartin

+4

@Default Dlaczego? Ponieważ lubią quizować się na dziwnym kodzie C#? – Erix

Odpowiedz

40

To jest stara łamigłówka i jest dość trudna. Kiedy dałem go samemu Andersowi, nie otrzymał odpowiedzi za pierwszym razem!

myślę wersja Twój współpracownik dał pan jest z bloga Cyrusa:

http://blogs.msdn.com/b/cyrusn/archive/2005/08/01/446431.aspx

Nieco prostsza wersja jest na moim blogu.

http://blogs.msdn.com/b/ericlippert/archive/2007/07/27/an-inheritance-puzzle-part-one.aspx

Rozwiązaniem mojej wersji jest tutaj:

http://blogs.msdn.com/b/ericlippert/archive/2007/07/30/an-inheritance-puzzle-part-two.aspx

skrócie powodem zamieszania zachowania jest to, że gdy masz imię, które występuje zarówno w zewnętrznej klasie oraz klasa podstawowa, klasa podstawowa "wygrywa". Oznacza to, że jeśli masz:

public class B 
{ 
    public class X {} 
} 
public class P 
{ 
    public class X 
    { 
    public class D : B 
    { 
     public class N : X {} 
    } 
    } 
} 

następnie P.X.D.N dziedziczy B.X, a nie z P.X. Układanka tworzy zagnieżdżone generyczne typy w taki sposób, że ta sama deklaracja może być nazwana zarówno przez "zewnętrzne", jak i "podstawowe" ścieżki wyszukiwania, ale ma różne różne znaczenia w każdym z nich z powodu ogólnej konstrukcji.

W każdym razie przeczytaj wyjaśnienie na blogu, a jeśli nadal nie jest jasne, zadaj bardziej szczegółowe pytanie.

8

Ok, moja pierwsza odpowiedź była błędna. Ważne jest zagnieżdżenie:

w o.b.GetType() b jest członkiem otaczającej klasy, która jest tworzona jako B<char>, która dziedziczy po A<char>, co z kolei powoduje, że T1 jest równe char. Co nie jest całkiem jasne jest następujący (instrukcja instancji dla A_int.B_char.C_bool):

public class A_bool 
{ 
    public bool a; 

    public class B_bool : A_bool 
    { 
     public bool b; 
    } 
} 

public class A_char 
{ 
    public char a; 

    public class B_bool : A_bool 
    { 
     public char b; 
    } 
} 

public class A_int 
{ 
    public int a; 

    public class B_char : A_char 
    { 
     public int b; 

     public class C_bool : A_char.B_bool 
     { 
      public int c; 
     } 
    } 
} 

Tutaj C_bool mogły pochodzić z A_bool.B_bool jak dobrze, prawda? Ale ponieważ jesteśmy zagnieżdżeni w A_char, jest to preferowane.

+1

Dlaczego więc o.c nie jest boolem? Ponieważ C dziedziczy po B , która z kolei dziedziczy po A .. –

+1

Tak, co jest mylące, to różnica między dziedziczeniem a typami obejmującymi. 'C ' jest zawarte w 'B ' ale dziedziczy po 'B ' – CubeSchrauber

+0

To dobry sposób na zilustrowanie sytuacji! –