2017-02-16 23 views
0

У меня есть пространство имен в проекте с ссылкой, Project.Base, и кто-то подумал, что было бы неплохо объявить свой собственный общий класс List в этом пространстве имен.Почему использование пространств имен работает неинтуитивно?

Теперь у меня есть файл с кодом, который начинается:

using System.Collections.Generic; 
using Project.Base.Sub; 

Project.Base имен никогда на самом деле формально используется; просто вложенное пространство имен внутри него. System.Collections.Genericесть формально б/у. Но по какой-то причудливой причине, когда я объявляю метод, тип возврата которого равен List<T>, он интерпретирует это как Project.Base.List<T>, а не System.Collections.Generic.List<T>!

Это кажется невероятно противоречивым для меня. Кто-нибудь знает, что происходит и как это исправить?

EDIT Для воспроизведения:

using System; 
using System.Collections.Generic; 
using Project.Base.Sub; 

namespace Project.Base 
{ 
    public class List<T> { } 
} 

namespace Project.Base.Sub { } 

namespace Project.Base.Sub2 
{ 

    public class P 
    { 
     public static void Main() 
     { 
      var list = new List<int>(); 
      Console.WriteLine(list.GetType().Namespace); 
      Console.Read(); 
     } 
    } 
} 

(. Обратите внимание, что код в вопрос находится в другом суб-пространстве имен Project.Base Это представляется значительным.)

+0

Не могли бы вы разместить код для пространства имен Project.Base.Sub? Или, по крайней мере, начало –

+0

В каком пространстве имен существует код, который ссылается на «Список »? –

+2

'имен Project.Base { \t Список общественного класса {}} имен Project.Base.Sub {} имен Foo { \t с использованием System.Collections.Generic; \t using Project.Base.Sub; \t \t общественного класса P \t { \t \t государственной статической силы Main() \t \t {список \t \t \t вар = новый список (); \t \t \t System.Console.WriteLine (list.GetType(). Пространство имен); \t \t} \t} } 'Ваша заявленная проблема не может быть воспроизведена. ** Почтовый код, который фактически воспроизводит проблему **. –

ответ

2

поиск Название поступления путем поиска через охватывающие пространства имен и только с учетом директив using, которые находятся в области каждого из них.

Чтобы сделать эту компиляцию, вы можете переместить using директиву внутри:

using System; 

namespace Project.Base 
{ 
    public class List<T> { } 
} 

namespace Project.Base.Sub { } 

namespace Project.Base.Sub2 
{ 
    using System.Collections.Generic; 

    public class P 
    { 
     public static void Main() 
     { 
      var list = new List<int>(); 
      Console.WriteLine(list.GetType().Namespace); 
      Console.Read(); 
     } 
    } 
} 

верхнего уровня using директивы только в глобальном пространстве имен, и так будет искать только в случае поиска в ограждающих пространств имен не удается. Итак, первый поиск не находит Project.Base.Sub2.List, но затем на следующем уровне он расположен Project.Base.List. Если это не удалось, оно попыталось бы найти тип Project.List.

Другая директива using была красной селедкой.

2

Принятый ответ верен. Другой способ понять проблему в том, что Опубликованный код в точности эквивалентен

using System; 
using System.Collections.Generic; 
using Project.Base.Sub; 

namespace Project 
{ 
    namespace Base 
    { 
    public class List<T> { } 
    namespace Sub { } 
    namespace Sub2 
    { 
     public class P 
     { 
     public static void Main() 
     { 
      var list = new List<int>(); 
      Console.WriteLine(list.GetType().Namespace); 
      Console.Read(); 
     } 
     } 
    } 
    } 
} 

И теперь должен быть ясно, почему List решает, как это делает. Объявление List находится непосредственно в закрытом пространстве имен.

С точки зрения дизайна было бы хорошей идеей для вас вернуться к своему коллеге, который думает, что наименование класса «Список» - хорошая идея. Часто указывается, что существуют пространства имен для предотвращения конфликтов имен, но на самом деле это их вторичная цель. В реалистичном коде обычно не так много конфликтов имен, потому что люди обычно не путают такие вещи, как назвать их собственный класс «Список».

Основная цель пространств имен является организовать код в логические группы, так что вы можете использовать using «тянуть в рамки» имена вещей, которые вы, вероятно, использовать в своей программе. Это позволяет IntelliSense лучше справляться с пониманием того, что вы имеете в виду при вводе текста, упрощает чтение кода и т. Д.Если вы обнаружите, что используете пространства имен для предотвращения конфликтов имен, вам может потребоваться решить, могут ли эти конфликты быть устранены некоторыми тактическими переименованиями.

+0

Действительно ли вы опубликовали на самом деле? Я понятия не имел, что язык C# позволяет вам встраивать блоки namespace. (99,99% кода, который я видел, использует один блок «namespace», чтобы заключить весь файл, за исключением заголовков комментариев и «использования» операторов, а остальное - либо тесты, либо примеры.) –

+1

@MasonWheeler: Спецификация C# четко заявляет, что 'namespace Foo.Bar {}' равно * точно так же, как 'namespace Foo {namespace Bar {}}'. Код действителен; Я призываю вас запустить его, если у вас есть сомнения. Я отмечаю, что я бы не считал этот код хорошим *, но он * действителен *. –

+0

@MasonWheeler: Если вам интересно узнать больше о пространствах имен, которые вы еще не знаете, вам может потребоваться прочитать https://blogs.msdn.microsoft.com/ericlippert/tag/namespaces/ –