2015-08-19 19 views
24

Ho appena letto questo interessante articolo di Eric Lippert, Top 10 Worst C# Features. Vicino alla fine, afferma:Che cosa significa Eric Lippert per "è necessario sapere qual è la classe base per determinare quale sia la classe base"?

Le regole per la risoluzione dei nomi dopo i due punti sopra indicati non sono ben fondate; si può finire in situazioni in cui è necessario sapere cosa la classe base è al fine di determinare quale sia la classe base.

Per due punti si riferisce all'operatore dell'ereditarietà (ad esempio Dog : Animal).

A quale situazione si riferisce Eric? Qualcuno può fornire un esempio di codice?

+10

Perché non chiedere questo nei commenti per l'articolo. Avresti una migliore possibilità che Eric lo vedesse e in realtà solo lui può rispondere a quello che intendeva. C'è anche il suo [blog entry] (http://ericlippert.com/2015/08/18/bottom-ten-list/) che si collega a questo. – juharr

+0

Immagino che questo sia un errore, potrebbe voler dire: è necessario sapere quale sia la classe base per determinare quale sia la ** classe derivata **. –

+4

@MenelaosVergis: Sono abbastanza sicuro che non sia un errore. – SLaks

risposta

21

Questo può accadere in scenari contorti con i generici, l'ereditarietà e classi annidate:

class Base<T> { 
    public class Inner {} 
} 

class Derived : Base<Derived.Inner2> { 
    public class Inner2 : Inner {} 
} 

Result

  • Per determinare Derived 's classe base, abbiamo bisogno di legare Derived.Inner2.
  • Per il binding Derived.Inner2, è necessario risolvere il simbolo Inner.
  • Il simbolo Inner viene ereditato dalla classe base dell'ambito contenente, pertanto è necessario determinare nuovamente la classe base Derived.
+1

Ottima risposta. Molto divertente giocare con questo codice e 'ToString'. –

+0

@IanNewson: Grazie! TryRoslyn (vedi il mio link) è in realtà un modo più conveniente per vedere cosa sta succedendo. – SLaks

+0

Oh e questo non è diretto all'autore di questa risposta in particolare, ma non vedo perché Eric considererebbe questo un problema? È un caso limite lontano e C# lo gestisce bene. –

14

SLaks offre una buona risposta; guarda i miei commenti per alcune note aggiuntive.

Come ho detto nei commenti, sto cercando le mie vecchie note su questo argomento e se le trovo, scriverò un blog. Ecco un divertente esempio aggiuntivo. Questo programma è legale. I significati di N nella dichiarazione di classe e la dichiarazione di campo sono uguali o diversi? Se sono uguali, cos'è un'espressione di tipo pienamente qualificato per loro? Se sono diversi, perché le specifiche richiedono che siano diversi?

public class N {} 
public class B<T> 
{ 
    public class N {} 
} 

public class D : B<N> // base class 
{ 
    N n; // field 
} 

Questo illustra il problema fondamentale: ricerca dei nomi richiede che la classe di base è noto, ma la classe base viene cercato per nome.

Ora pensa a come le interfacce funzionano nel mix. Supponiamo che la classe D implementa anche un'interfaccia IN, analogamente annidata in B e disponibile globalmente. La ricerca dell'interfaccia risolve la classe base o il namespace globale? Queste sono le domande che devi risolvere quando stai scrivendo un compilatore.

+0

Supponendo uno spazio globale globale 'Globale',' B 'è pienamente qualificato come' B ', e' N n; 'si riferisce alla classe nidificata quindi è pienamente qualificato come' B .N n; '. Se si desidera che il 'N' in' classe D: B 'sia il' n' nidificato, si dovrebbe fornire un parametro di tipo, ad es. 'classe D: B .N>'. Ovviamente 'sometype' può essere' B ', o anche' B .N', ad es. 'classe pubblica D: B .N >>. N >>. N> .N >>. N>' e così via. – Galax

+0

Ho copiato e incollato l'idea molto più a fondo, e a circa 700 livelli di generici nidificati (che spero siano più che sufficienti per chiunque ...) ho finalmente ricevuto l'errore 'The User Diagnostic Analyzer 'Microsoft.CodeAnalysis .CSharp.Diagnostics.SimplifyTypeNames.CSharpSimplifyTypeNamesDiagnosticAnalyzer 'ha generato un'eccezione di tipo' System.InsufficientExecutionStackException 'con messaggio' Stack insufficiente per continuare a eseguire il programma in modo sicuro. Questo può accadere dall'avere troppe funzioni sullo stack di chiamate o sulla funzione nello stack usando troppo spazio nello stack. – Galax

+1

@Galax: In effetti, c'era un tester sul team di compilatori C# che si dilettava nel trovare situazioni come quella che avrebbe far esplodere l'analizzatore. In alcuni casi abbiamo sostituito gli algoritmi ricorsivi con quelli iterativi e in alcuni lo lasciamo scoppiare, supponendo che tali programmi non siano realistici. –