Прежде всего, давайте согласимся с тем, что пространство имен должно соответствовать структуре папок и что каждый языковой артефакт должен находиться в отдельном файле.
(см. Должны ли папки в решении соответствовать пространству имен?).
Следующий вопрос - как на самом деле должны быть организованы папки на диске. Предположим, у меня есть ClassC в пространстве имен A.B.C и ClassD в пространстве имен A.B.C.D. Предположим также, что каждое пространство имен встроено в свою собственную сборку (проект) и что пространства имен имеют зависимости справа налево в соответствии с принятой передовой практикой (A.B.C.D может зависеть от A.B.C, который может зависеть от A.B, который может зависеть от A). Я понимаю, что каждое пространство имен не обязательно должно быть в отдельной сборке, но в общем случае у нас будет несколько пространств имен в отдельных сборках, и мой пример иллюстрирует это.
Я вижу (по крайней мере) два способа создания дерева папок, которые я назову «вложенными папками» и «плоскими папками»:
A
--A.csproj
--B
---- A.B.csproj
---- C
------ A.B.C.csproj
------ classC.cs
------ D
-------- A.B.C.D.csproj
-------- classD.cs
ИЛИ ЖЕ
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
Вы увидите, что я уже сделал несколько предположений:
Вложенные папки кажутся более естественными (все мы любим иерархии), но в больших решениях может быть немного сложнее ориентироваться:
Когда вы смотрите на свое решение в VS, оно показывает плоский список проектов, а не вложенное представление. Это больше похоже на «плоские папки», поэтому может быть полезно организовать папки на диске в соответствии с представлением в VS.
Если вы посмотрите в каждую папку на диске, вы увидите артефакты папки для этого проекта плюс подпапку для пространства имен: взяв C в качестве примера:
C
--bin
--D
--obj
--Свойства
--A.B.C.csproj
--classC.cs
В зависимости от настоящего имени D может быть неочевидным, что D - это папка пространства имен, а не папка организации в пространстве имен C.
Я знаю, что у нас были папки и пространства имен с первого дня в .NET (8 или 9 лет назад), а в Java и до этого, но, лично говоря, мы, похоже, не пришли к консенсусу в отношении наилучшей практики организации проектов для крупных компаний. решения. Мне было бы действительно интересно узнать, что вы все думаете.
Спасибо Майкл





«Прежде всего, давайте согласимся, что пространство имен должно соответствовать структуре папок и что каждый языковой артефакт [sic] должен находиться в отдельном файле».
Забавно, вот как пакеты работают в Java. Я всегда думал, что разрыв связи между пространствами имен и структурой каталогов считался одним из улучшений, внесенных C#. Это не правда? (Простите за незнание, я Java-человек.)
Я всегда делал вложенную иерархию. Это делает до боли очевидным, где добавлять новые проекты к существующему решению, и сохраняет ваши пространства имен хорошо организованными на диске. Это также делает более очевидным разделение пространства имен и проекта.
Я не большой поклонник вложенных проектов, поскольку они закапывают проекты глубоко внутри структуры, и если вам нужно повторно использовать этот проект в другом приложении, что вы будете делать, скопировать / вставить код? Мне нравится следовать некоторой плоской структуре, но организованной по пространству имен.
Вот как я это делаю:
- 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. в примере), поэтому вы можете просто ссылаться на нее напрямую.
Я использую плоский подход. Мне слишком сложно поддерживать вложенную иерархию. Я группирую свои проекты в несколько решений с учетом максимальной возможности повторного использования и перекрестных ссылок, и всегда находил это удовлетворительным. Пример (проекты с отступом):
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
и т. д. и т. д.
Обновлено: удалено бредовое замечание
Я думаю, вам нужно определить точку отсечения, когда плоский подход больше не работает. Например, если у вас есть типичная трехуровневая архитектура в небольшом проекте, наличие трех проектов на внешнем уровне не проблема. Однако, если у вас есть несколько десятков, то какая-то группировка помогает сегментировать функциональность и делает все решение более понятным.
Да, но разве тогда не практичнее просто запустить новое (под) решение вместо того, чтобы иметь десятки проектов в одном? В любом случае, в конце концов, все дело в личных предпочтениях ..
Если вы используете вложенные проекты, вы рискуете столкнуться с проблемой 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
Я предпочитаю плоскую структуру с проектами в корне.
Внутри у меня есть различные папки и пространства имен. Я создаю разные сборки только для развертываемых модулей. В небольших приложениях даже не будет такого разделения. ИМО, это упрощает задачу. Если я когда-нибудь решу, что код, который у меня есть, нужно использовать где-то еще, достаточно легко разбить его на сборку, если это необходимо, если я соблюдаю хорошие методы размещения имен.
12 лет спустя, есть ли какой-либо окончательный или лучший ответ на этот вопрос?
Я хотел бы использовать структуру вложенных папок, однако, учитывая, что вы:
"agree that namespace should match folder structure and that each language artefact should be in its own file."
Как бы выглядела структура папок проекта A.B.C.csproj, если бы он расширял код из других пространств имен, например:
Возможно что-то вроде:
/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
Выше пытается продемонстрировать:
Вы правы, нет прямой связи между папками, именами файлов, пространствами имен и именами типов. Однако это соглашение, поэтому файлы легче находить, но вы можете смешивать и сопоставлять их по своему усмотрению.