2010-07-01 5 views
6

Betrachten Sie das folgende kurze Code-Snippet.Können Sie diesen Randfall mit dem Schlüsselwort C# 'using' bei Namespace-Deklarationen und -Mitgliedern erklären?

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; } 
     } 
    } 
} 

Setzen Sie sich mit Beispiel # 1 zuerst vertraut.

using B; 

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

Betrachten wir nun Beispiel # 2.

In Beispiel 1 ist nichts besonders Seltsames. Bei Beispiel 2 wird es jedoch interessant. Achten Sie unbedingt auf alle in den Beispielen verwendeten Bezeichner. Als eine lustige Übung versuchen Sie zu erraten, was passiert, ohne dies in den Compiler zu stecken. Ich werde die Antwort hier nicht verraten, weil 1) es einfach genug ist, es selbst zu versuchen und 2) Ich möchte den Spaß nicht ruinieren.

Wird das Programm:

  • kompilieren nicht
  • Anzeige B.Foo
  • Anzeige ABFoo

Die Frage ... Wo in der C# Spezifikation ist dieses Verhalten beschrieben ?

Ich habe einen Blick auf Abschnitt 3.7 in der C# 4.0-Spezifikation und vor allem Kugel # 2, aber ich glaube nicht, dass das das Verhalten erklärt. Wenn überhaupt, dann kann ich fast glauben, dass der Compiler sich der Spezifikation widerspricht.

+0

Sie sollten diese Frage an den Autor dieses Blogs senden: http://blogs.msdn.com/b/ericlippert/ Er wird absolut eine Antwort für Sie haben. – David

+0

Ich kenne seinen Blog. Er postet oft auf SO, damit er einen Stich hier machen kann. –

+0

Ja, ich erwarte Erics Antwort selbst :) –

Antwort

7

das erste Beispiel druckt „B.Foo“, das zweite Beispiel druckt „ABFoo“ zu ACB lösen. Dies liegt daran, dass im zweiten Beispiel die using B; Direktive in den Namespace A.C eingeschlossen ist.

Warum verwendet es A.B statt B?

Da Namespace-Lookups den gleichen Regeln folgen wie Typ-Name-Qualifikations-Lookups. Section 3.8 der C# -Spezifikation.

Grundsätzlich, wenn die using Direktive vom Compiler verarbeitet wird, wird das Symbol B im Namespace A.C gesucht. Nicht gefunden, es ist in der Namespace A gesucht.Da es dort als Sub-Namespace von A gefunden wird, wählt es diesen Namespace aus und wechselt nicht zum globalen Namespace, um den Namespace B zu finden.

Edit:
Wie @ P.Brian.Mackey schon sagt, können Sie zum B Namespace mit using global::B; bekommen.

+1

Ja, ich denke du hast Recht. Das relevante Stück ist in 3.8 bullet # 1 sub-bullet # 2. Es beschreibt definitiv dieses Backtracking-Verhalten, aber nicht so deutlich. Netter Fang. –

+0

@Brain: Das ist die eine, zusammen mit den drei Kugeln nach. – Randolpho

5

Ich habe die C# Spezifikationen nicht gelesen, aber ich kann Ihnen sagen, was passiert, einfach durch Abzug. Wenn Sie B innerhalb des A.C-Namespace verwenden, befinden Sie sich nicht mehr im globalen Gültigkeitsbereich, Sie befinden sich im Bereich des umgebenden Namespace. Zunächst wird die App wird versuchen, in AC, dann in A. zu lösen

Die einfachste Lösung ist einfach, um die innen mit Aussage zu ändern:

using global::B; 

Aber Sie weiter diesen auftretenden durch Zugabe von

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

Beachten Sie, dass Sie jetzt

+0

+1, aber ich denke, Sie haben die Reihenfolge, in der Auflösung rückwärts auftritt. Es sollte versuchen zuerst in 'A.C' und dann' A' aufzulösen. – Randolpho

+1

Vielen Dank für die Korrektur. Es wurde gemacht. –

+0

Guter Tipp auf den 'Global :: B' Trick übrigens. –

0

glaube ich, dass die relevanten Teile der Spezifikation sind:

3.4.1 Namespace Mitglieder

Namespaces und Typen, die keine einschließenden Namespace haben Mitglieder des globalen Namensraum sind. Dies entspricht direkt den Namen in der globalen Deklaration Raum deklariert.

Namespaces und Typen, die in einem Namespace deklariert sind, sind Mitglieder dieses Namespace . Dies entspricht direkt den im Deklarationsbereich des Namensraums deklarierten Namen.

Namespaces haben keinen Zugriff Einschränkungen. Es ist nicht möglich, deklarieren private, geschützte oder interne Namespaces und Namespace Namen sind immer öffentlich zugänglich.

In Abschnitt 9.4.2 wird erläutert, wie sich die Verwendung von Direktiven auf die Bereichsauflösung von Kennungen auswirkt.

4

Die anderen Antworten sind korrekt, aber eine zusätzliche Anmerkung. Es hilft, sich daran zu erinnern, dass

namespace A.C 
{ 
    using B; 

eigentlich nur einen kurzen Weg des Schreibens ist

namespace A 
{ 
    namespace C 
    { 
     using B; 

, die es ein bisschen mehr klar machen könnte, was hier vor sich geht. Wenn B Lösung überprüfen wir A für B, bevor wir den Behälter von A. überprüfen

Wenn Sie in einer Weise interessiert sind, die Namespace-Lookups schief gehen kann, meine Reihe von Artikeln über das sehen:

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

+0

Netter Blog, danke. –

Verwandte Themen