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

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

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

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

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

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

A
--A.csproj
--B
---- A.B.csproj
---- C
------ A.B.C.csproj
------ classC.cs
------ D
-------- A.B.C.D.csproj
-------- classD.cs

ИЛИ ЖЕ

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

A
--A.csproj
A.B
--A.B.csproj
A.B.C
--A.B.C.csproj
--classC.cs
A.B.C.D
--A.B.C.D.csproj
--classD.cs

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

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

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

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

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

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
15
0
25 117
8

Ответы 8

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

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

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

Lasse V. Karlsen 30.12.2008 21:17

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

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

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

- 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)

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

Во вложенной модели весь проект существует в папке с именами, разделенной точками (например, A.B.C. в примере), поэтому вы можете просто ссылаться на нее напрямую.

Robert C. Barth 30.12.2008 23:09

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

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

и т. д. и т. д.

Обновлено: удалено бредовое замечание

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

Да, но разве тогда не практичнее просто запустить новое (под) решение вместо того, чтобы иметь десятки проектов в одном? В любом случае, в конце концов, все дело в личных предпочтениях ..

user39603 31.12.2008 13:35

Если вы используете вложенные проекты, вы рискуете столкнуться с проблемой Windows 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 и настоящий оффлайн рассказ)

Такой же риск существует при использовании плоской структуры папок. src \ Abc.Def.Project1 такой же длины, как SRC \ Abc \ Def \ Project1

user247702 05.05.2011 12:59

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

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

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

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

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

"agree that namespace should match folder structure and that each language artefact should be in its own file."

Как бы выглядела структура папок проекта 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 уровень на подчеркивание

Другие вопросы по теме