Пространства имен и структуры папок в решениях c #: как должны быть организованы папки на диске?

Прежде всего, давайте согласимся с тем, что пространство имен должно соответствовать структуре папок и что каждый языковой артефакт должен находиться в отдельном файле.

(см. Должны ли папки в решении соответствовать пространству имен? ).

Следующий вопрос заключается в том, как на самом деле папки должны быть организованы на диске.
Предположим, у меня есть ClassC в пространстве имен ABC и ClassD в пространстве имен ABCD.
Давайте также предположим, что каждое пространство имен встроено в свою собственную сборку (проект) и что пространства имен имеют зависимости справа налево в соответствии с принятой передовой практикой (ABCD может зависеть от ABC, который может зависеть от AB, который может зависеть от A). Я понимаю, что каждое пространство имен не обязательно должно быть в отдельной сборке, но в общем случае у нас будет несколько пространств имен в отдельных сборках, и мой пример иллюстрирует это.

Я вижу (по крайней мере) два способа создания дерева папок, которые я назову «вложенными папками» и «плоскими папками»:

1 - Вложенные папки:

A
--A.csproj
--B
---- ABcsproj
---- C
------ ABCcsproj
---- --classC.cs
------ D
-------- ABCDcsproj
-------- classD.cs

OR

2 - Плоские папки:

A
--A.csproj
AB
--ABcsproj
ABC
--ABCcsproj
--classC.cs
ABCD
--ABCDcsproj
--classD.cs

Вы увидите, что я уже сделал несколько предположений:

  • Каждый файл проекта имеет полное имя (FQN) на основе пространства имен.
  • Каждый файл класса использует не-FQN

Вложенные папки кажутся более естественными (все мы любим иерархии), но в больших решениях может быть немного сложнее ориентироваться:

Когда вы смотрите на свое решение в VS, оно показывает плоский список проектов, а не вложенное представление. Это больше похоже на «плоские папки», поэтому может быть полезно организовать папки на диске в соответствии с представлением в VS.

Если вы посмотрите в каждую папку на диске, вы увидите артефакты папки для этого проекта плюс подпапку для пространства имен: взяв C в качестве примера:

C
--bin
--D
--obj
--Свойства
--A.B.C.csproj
--classC.cs

В зависимости от настоящего имени D может быть неочевидным, что D - это папка пространства имен, а не папка организации в пространстве имен C.

Я знаю, что у нас были папки и пространства имен с первого дня в .NET (8 или 9 лет назад), а в Java и до этого, но, лично говоря, мы, похоже, не пришли к консенсусу в отношении наилучшей практики организации проектов для крупных компаний. решения. Мне было бы действительно интересно узнать, что вы все думаете.

Спасибо, Майкл


person Micdev42    schedule 30.12.2008    source источник


Ответы (8)


Я использую плоский подход. Мне слишком сложно поддерживать вложенную иерархию. Я группирую свои проекты в несколько решений с учетом максимальной возможности повторного использования и перекрестных ссылок, и всегда находил это удовлетворительным. Пример (проекты с отступом):

CompanyName
  CompanyName.Core
    Class1
    Struct2
    Enum3
  CompanyName.Data
  CompanyName.Web

CompanyName.Projects
  CompanyName.Projects.Core

CompanyName.Projects.ProjectX
  CompanyName.Projects.ProjectX.Core
  CompanyName.Projects.ProjectX.Website
  CompanyName.Projects.ProjectX.ToolY

и т. д. и т. д.

Изменить: удалено бредовое замечание

person user39603    schedule 31.12.2008

Я не большой поклонник вложенных проектов, поскольку они закапывают проекты глубоко внутри структуры, и если вам нужно повторно использовать этот проект в другом приложении, что вы будете делать, скопировать / вставить код? Мне нравится следовать некоторой плоской структуре, но организованной по пространству имен.

Вот как я это делаю:

- DataHelpers\
---Factory\
---DataAccess\
---...
- Components\
--- EmailProcessor\
--- ErrorLogger\
- Desktop\
--- WindowsApp1\
- Services\
--- WindowsService1\
--- WindowsService2\
- WebApps\
--- WebApp1\
--- WebApp2\

Теперь внутри каждого основного приложения, которое у меня есть, например:

- WindowsService1\
--- WindowsService1\ (this contains all *.cs, bin, obj, etc and .csproj file)
--- Solution\ (this contains the .sln file where you link to other projects like ErrorLogger, etc)

Надеюсь это имеет смысл!

person Ricardo Villamil    schedule 30.12.2008
comment
Во вложенной модели весь проект существует в папке с именами, разделенной точками (например, A.B.C. в примере), поэтому вы можете просто ссылаться на нее напрямую. - person Robert C. Barth; 30.12.2008

«Прежде всего, давайте согласимся, что пространство имен должно соответствовать структуре папок и что каждый языковой артефакт [sic] должен находиться в отдельном файле».

Забавно, вот как пакеты работают в Java. Я всегда думал, что разрыв связи между пространствами имен и структурой каталогов считается одним из улучшений, внесенных C #. Это не правда? (Простите за незнание, я Java-человек.)

person duffymo    schedule 30.12.2008
comment
Вы правы, нет прямой связи между папками, именами файлов, пространствами имен и именами типов. Однако это соглашение, поэтому файлы легче находить, но вы можете смешивать и сопоставлять их по своему усмотрению. - person Lasse V. Karlsen; 30.12.2008

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

person Robert C. Barth    schedule 30.12.2008

Если вы используете вложенные проекты, вы рискуете попасть в окна MaxPath. Это серьезный отказ от использования вложенных структур. Только представьте, что встречаетесь с этим маленьким Gem на полпути через проект разработчика, когда вам нужно называть проекты VS трехбуквенными акронимами, чтобы не попасть в MaxPath. Ошибка MS послужила источником вдохновения для названий ваших сборок. Что это за шутка. Работать с плоскими конструкциями намного удобнее со всех сторон.

   -SouceControlFolderName
     -Project1
       -Src
         -Main
           -Company.Project1.AppName
             *Company.Project1.AppName.sln
             *Company.Project1.AppName.Tests.sln
             -Company.Project1.AppName.Common
             -Company.Project1.AppName.Common.Tests
             -Company.Project1.AppName.Entities
             -Company.Project1.AppName.Entities.Tests
             -Company.Project1.AppName.Security
             -Company.Project1.AppName.Security.Tests
             -etc.

Вы можете создать отдельный каталог для тестовых проектов или, как указано выше, и хранить их все вместе, что проще управлять при добавлении в систему управления версиями, то есть Subversion (TFS во многих отношениях лучше, за исключением того факта, что ему нужна интеграция с Explorer, а не только интеграция с VS и настоящий оффлайн рассказ)

person Microsoft Developer    schedule 02.02.2011
comment
Такой же риск существует при использовании плоской структуры папок. src \ Abc.Def.Project1 имеет ту же длину, что и src \ Abc \ Def \ Project1 - person user247702; 05.05.2011

Я думаю, вам нужно определить точку отсечения, когда плоский подход больше не работает. Например, если у вас есть типичная трехуровневая архитектура в небольшом проекте, наличие трех проектов на внешнем уровне не проблема. Однако, если у вас есть несколько десятков, то какая-то группировка помогает сегментировать функциональность и делает все решение более понятным.

person Dmitri Nesteruk    schedule 31.12.2008
comment
Да, но разве тогда не практичнее просто начать новое (под) решение вместо того, чтобы иметь десятки проектов в одном? В любом случае, в конце концов, все дело в личных предпочтениях .. - person user39603; 31.12.2008

Я предпочитаю плоскую структуру с проектами в корне.

  • MyCorp.Core
  • MyApp.Domain
  • MyApp.Data
  • MyApp.UI
  • MyApp.Test

Внутри у меня есть различные папки и пространства имен. Я создаю разные сборки только для развертываемых модулей. В небольших приложениях даже не будет такого разделения. ИМО, это упрощает задачу. Если я когда-нибудь решу, что код, который у меня есть, нужно использовать где-то еще, достаточно легко разбить его на сборку, если это необходимо, если я соблюдаю хорошие методы размещения имен.

person Fred    schedule 04.10.2013

12 лет спустя, есть ли какой-либо окончательный или лучший ответ на этот вопрос?

Я хотел бы использовать структуру вложенных папок, однако, учитывая, что вы:

«согласны с тем, что пространство имен должно соответствовать структуре папок и что каждый языковой артефакт должен находиться в отдельном файле».

Как бы выглядела структура папок проекта A.B.C.csproj, если бы он расширял код из других пространств имен, например:

  • прародитель: A.csproj
  • родитель: A.B.csproj
  • дочерний A.B.C.D.csproj
  • внешние пространства имен System.Linq или Microsoft.Extensions.Logging

Возможно что-то вроде:

/A                                  // namespace: A
  /B                                // namespace: A.B
    /C                              // namespace: A.B.C
      A.B.C.csproj 
      ClassC.cs                  
      /_                            // External Namespace root folder (underscore with no text)
        /System                     // namespace: System 
          /Linq                     // namespace: System.Linq
            IQueryableExtensions.cs 
        /Microsoft                  // namespace: Microsoft
          /Extensions               // namespace: Microsoft.Extensions
            /Logging                // namespace: Microsoft.Extensions.Logging
              ILoggerExtensions.cs                                  
      /__A                          // namespace: A (Grand Parent folder (2 underscores for 2 levels up)
        ClassAExtensions.cs
        /B                          // namespace: A.B (Nested Parent folder)
          ClassBExtensionsNested.cs
                                    //Parent Namespace folder (1 underscore for 1 level up)
      /_B                           // namespace: A.B
        ClassBExtensions.cs
      /D                            // namespace: A.B.C.D (Child folder)
        ClassDExtensions.cs

Выше пытается продемонстрировать:

  • Папка с одиночным подчеркиванием (_) без текста после нее будет заменена пустым пространством имен и новым корнем для всех внешних пространств имен.
  • Папки с нижним подчеркиванием (__A) и (_B), за которыми следуют текстовые заменители на уровень выше в дереве / иерархии текущего проекта. 1 уровень на подчеркивание
person tb-mtg    schedule 09.01.2020