2010-07-01 11 views
6

Si consideri il seguente frammento di codice breve.Puoi spiegare questo caso limite riguardante la parola chiave C# 'using' con dichiarazioni e membri dello spazio dei nomi?

namespace B 
{ 
    public class Foo 
    { 
     public string Text 
     { 
      get { return GetType().FullName; } 
     } 
    } 
} 

namespace A.B 
{ 
    public class Foo 
    { 
     public string Text 
     { 
      get { return GetType().FullName; } 
     } 
    } 
} 

acquisire familiarità con esempio # 1 prima.

using B; 

namespace A.C 
{ 
    public static class Program 
    { 
     public static void Main() 
     { 
      Console.WriteLine(new Foo().Text); 
     } 
    } 
} 

Ora consideriamo esempio # 2.

namespace A.C 
{ 
    using B; // Notice the placement here. 

    public static class Program 
    { 
     public static void Main() 
     { 
      Console.WriteLine(new Foo().Text); 
     } 
    } 
} 

Non c'è nulla di terribilmente di strano esempio # 1. Tuttavia, le cose si fanno interessanti con l'esempio # 2. È fondamentale prestare molta attenzione a tutti gli identificatori utilizzati negli esempi. Come esercizio divertente prova a indovinare cosa succede senza collegarlo al compilatore. Non ti svelerò la risposta qui perché 1) è abbastanza facile provare te stesso e 2) Non voglio rovinare il divertimento.

Sarà il programma:

  • non compilare
  • visualizzazione B.Foo
  • visualizzazione ABFoo

La domanda ... Dove nelle specifiche C# è questo comportamento descritto ?

Ho dato un'occhiata alla sezione 3.7 nella specifica C# 4.0 e in particolare al punto 2, ma non penso che questo spieghi il comportamento. Semmai mi sembra quasi che il compilatore si stia comportando in modo contraddittorio rispetto alle specifiche.

+0

Dovresti pubblicare questa domanda all'autore di questo blog: http://blogs.msdn.com/b/ericlippert/ Avrà assolutamente una risposta per te. – David

+0

Ho familiarità con il suo blog. Inserisce spesso su SO così da poter fare una pugnalata proprio qui. –

+0

Sì, sono in attesa della risposta di Eric me stesso :) –

risposta

7

il primo esempio stampe "B.Foo", il secondo esempio stampe "ABFoo". Questo perché nel secondo esempio la direttiva using B; è inclusa nello spazio dei nomi A.C.

Perché utilizza A.B anziché B?

Perché le ricerche dello spazio dei nomi seguono le stesse regole delle ricerche sulla qualifica del nome del tipo. Section 3.8 della specifica C#.

Fondamentalmente, quando la direttiva using viene elaborata dal compilatore, il simbolo B viene cercato nello spazio dei nomi A.C. Non trovandolo, è cercato nel namespace A.Poiché è presente come sottodominio di A, seleziona tale spazio dei nomi e non passa allo spazio dei nomi globale per trovare lo spazio dei nomi B.

Edit:
Come suggerisce @ P.Brian.Mackey, si può arrivare al B spazio dei nomi con using global::B;.

+1

Sì, penso che tu abbia ragione. Il pezzo rilevante è in 3.8 bullet # 1 sub-bullet # 2. Sicuramente, ma non così chiaramente, descrive questo comportamento di backtracking. Bella presa. –

+0

@Brain: Questo è quello, insieme ai tre proiettili dopo. – Randolpho

5

Io non ha ancora letto le specifiche # C, ma posso dirvi che cosa sta succedendo semplicemente per deduzione. Quando si inserisce B all'interno dello spazio dei nomi A.C non si è più nell'ambito globale, si è nell'ambito del namespace circostante. In primo luogo l'applicazione cercherà di risolvere in AC, poi in A.

La soluzione più semplice è semplicemente quello di cambiare l'interno istruzione using a:

using global::B; 

Ma, si può vedere ulteriormente questo si verificano con l'aggiunta di

namespace A.C.B 
{ 
    public class Foo 
    { 
     public string Text 
     { 
      get { return GetType().FullName; } 
     } 
    } 
} 

si noti che è ora di risolvere alla ACB

+0

+1, ma penso che tu abbia l'ordine in cui la risoluzione si verifica all'indietro. Dovrebbe cercare di risolvere prima in 'A.C', poi in' A'. – Randolpho

+1

Grazie per la correzione. È stato fatto –

+0

Un buon consiglio sul trucco 'global :: B' a proposito. –

0

Credo che le parti pertinenti del specifiche sono:

3.4.1 membri del namespace

spazi dei nomi e tipi che non hanno racchiude namespace sono membri del namespace globale. Questo corrisponde direttamente ai nomi dichiarati nella dichiarazione globale spazio.

Gli spazi dei nomi e i tipi dichiarati all'interno di uno spazio dei nomi sono membri di tale spazio dei nomi . Ciò corrisponde direttamente a ai nomi dichiarati nello spazio di dichiarazione dello spazio dei nomi.

Gli spazi dei nomi non hanno restrizioni . Non è possibile per dichiarare spazi dei nomi interni privati, protetti o e namespace i nomi sono sempre accessibili al pubblico.

Così come la sezione 9.4.2 che illustra come l'utilizzo delle direttive influisce sulla risoluzione degli identificatori nell'ambito.

4

Le altre risposte sono corrette, ma una nota aggiuntiva. Aiuta a ricordare che

namespace A.C 
{ 
    using B; 

in realtà è solo un breve modo di scrivere

namespace A 
{ 
    namespace C 
    { 
     using B; 

Il che potrebbe rendere un po 'più chiaro che cosa sta succedendo qui. Durante la risoluzione B controlliamo A per B prima controlliamo il contenitore di A.

Se siete interessati in modi che le ricerche dello spazio dei nomi possono andare terribilmente sbagliato, vedere la mia serie di articoli al riguardo:

http://blogs.msdn.com/b/ericlippert/archive/tags/namespaces/

+0

Bel blog, grazie. –

Problemi correlati