2014-04-04 7 views
7

Considerate questo:Perché devo qualificare come genitore per utilizzare un tipo annidato quando si eredita da un tipo generico?

[SomeAttr(typeof(Bar))] 
class Foo { 

    class Bar { 

    } 
} 

... e questo:

class Foo : ISomething<Bar> { 

    class Bar { 

    } 
} 

Il primo esempio viene compilato, il secondo no. Per utilizzare un riferimento di tipo nidificato quando si eredita da un tipo generico che deve qualificarsi con nome del tipo del genitore:

class Foo : ISomething<Foo.Bar> { 

    class Bar { 

    } 
} 

La mia domanda è: perché? e perché questa restrizione non si applica quando si fa riferimento a un attributo nel tipo genitore (primo esempio)?

+0

La mia ipotesi sarebbe che il compilatore elabora gli attributi di classe dopo aver compilato le classi? Ma non conosco abbastanza i componenti interni del compilatore per sapere come trovare/provare quella risposta. Domanda molto interessante però! – BateTech

+0

Qual è un esempio pratico di utilizzo di una classe figlio nidificata pubblica in questo modo? Perché avere una classe nidificata quando la classe genitore dipende dal figlio e basta renderla una classe nello stesso spazio dei nomi del genitore? – BateTech

+0

@BateTech Ho trovato questa limitazione quando si lavora con un generatore di codice che mi consente solo di iniettare il codice all'interno di una classe, per definire i miei metodi. –

risposta

6

Si tratta dello scope della dichiarazione. Si consideri il seguente codice:

namespace FooSpace 
{ 
    class Foo : ISomething<Bar> 
    { 
     class Bar { } 
    } 
} 

La riga di codice class Foo : ISomething<Bar> è nel FooSpace spazio dei nomi, ma non all'interno della classe Foo. A questo punto, Bar non ha alcun significato. Bar di per sé avrebbe solo un significato all'interno dello l'ambito della classe Foo stessa.

Per utilizzare la classe Bar in qualsiasi codice di fuori il classe Foo, è necessario qualificare come Foo.Bar. Questa regola si applica anche allo all'interno della dichiarazione di classe.

Perché è così? Non è possibile che il compilatore elabori automaticamente che si deve intendere lo Bar nidificato all'interno della stessa classe?

Beh, per prima cosa ci potrebbe essere potenzialmente altre classi nidificate chiamati Bar all'interno di altre classi nello stesso spazio dei nomi, come segue:

namespace FooSpace 
{ 
    class Foo : List<Foo.Bar> 
    { 
     public class Bar { } 
    } 

    class Foo2 : List<Foo2.Bar> 
    { 
     public class Bar { } 
    } 
} 

Senza la qualificazione, che Bar vuoi dire? Il compilatore non avrebbe avuto modo di dirlo. Quindi è molto più coerente per il compilatore non tentare di indovinare, ma per insistere su un nome di classe esplicitamente qualificato.

Per quanto riguarda il caso di attributo, anche se un attributo class-targeting è dichiarato sopra la dichiarazione della classe in questo modo:

[SomeAttr(typeof(Bar))] 
class Foo { ... 

in realtà, il compilatore traduce questo a qualcosa di più simile a questo:

class public auto ansi beforefieldinit FooSpace.Foo extends [mscorlib]System.Object 
{ 
    .custom instance void FooSpace.SomeAttr::.ctor ... etc. 

In altre parole, l'oggetto dell'attributo viene creato all'interno della classe utilizzando il parametro fornito. Questo parametro typeof(Bar) è ovviamente valido, poiché esiste nell'ambito di classe di Foo.

La domanda correlata here discute anche questo caso.

E 'interessante notare che esattamente le stesse regole e comportamenti si applicano agli attributi di classe che accedono i membri della classe const o statici - non è necessario il specificare il nome della classe, perché l'attributo è effettivamente creato all'interno della classe.

+0

Questo non spiega perché funzioni con gli attributi. –

+0

Questa risposta ha senso, ma non risponde perché l'attributo sulla classe genitore con un riferimento alla classe "bar" compila correttamente. – BateTech

+0

Lo aggiungerò come una modifica. – Baldrick

Problemi correlati