c#解决方案中的命名空间和文件夹结构:如何组织磁盘上的文件夹?

时间:2008-12-30 17:36:51

标签: c# namespaces solution

首先,让我们同意命名空间应该匹配文件夹结构,并且每个语言工件应该在它自己的文件中。

(见Should the folders in a solution match the namespace?)。

接下来的问题是如何在磁盘上实际组织文件夹 假设我在A.B.C命名空间中有ClassC,在A.B.C.D命名空间中有ClassD 我们还假设每个命名空间都构建在自己的程序集(项目)中,并且根据公认的最佳实践,命名空间从右到左具有依赖性(A.B.C.D可以依赖于A.B.C,它可以依赖于A.B,它可以依赖于A)。我感谢每个命名空间不必在一个单独的程序集中,但在一般情况下,我们将在单独的程序集中有一些名称空间,我的示例说明了这一点。

我可以看到(至少)两种创建文件夹树的方法 - 我称之为“嵌套文件夹”和“平面文件夹”:

1 - 嵌套文件夹:

一个
--A.csproj
--B
---- A.B.csproj
----Ç
------ A.B.C.csproj
------ classC.cs
------ d
-------- A.B.C.D.csproj
-------- classD.cs

OR

2 - 平面文件夹:

一个
--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为例:

Ç
--bin
--D
--obj
--properties
--A.B.C.csproj
--classC.cs

根据D的真实姓名,D可能并不明显是命名空间文件夹而不是C命名空间中的组织文件夹。

我知道我们在.NET(8或9年前)和Java之前的第一天就有文件夹和命名空间,但是,就个人而言,我们似乎没有就最佳实践项目达成共识组织大型解决方案。我真的很想知道你们都在想什么。

感谢
迈克尔

8 个答案:

答案 0 :(得分: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

等。等

编辑:删除废话评论

答案 1 :(得分:5)

我不是嵌套项目的忠实粉丝,因为它将项目深埋在结构内部,如果你需要在另一个应用程序中重用该项目,那么你做了什么,复制/粘贴代码? 我喜欢遵循某种扁平结构,但是按命名空间组织。

我就是这样做的:

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

我希望这是有道理的!

答案 2 :(得分:3)

“首先,让我们同意命名空间应该匹配文件夹结构,并且每个语言工件[sic]应该在它自己的文件中。”

很有趣,这就是Java在Java中的工作方式。我一直认为打破命名空间和目录结构之间的联系被认为是C#引入的改进之一。这不是真的吗? (原谅我的无知,我是一个Java人。)

答案 3 :(得分:3)

我一直在做嵌套层次结构。它使得将新项目添加到现有解决方案的位置变得非常明显,并使您的命名空间在磁盘上得到很好的组织。它还使命名空间与项目的划分更加明显。

答案 4 :(得分:2)

如果您使用嵌套项目,则可能会遇到触及Windows MaxPath问题的风险。 这对于使用嵌套结构来说是一个巨大的破坏者。想象一下,通过一个开发项目中途遇到这个小宝石,不得不用三个字母的首字母缩写命名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整合和适当的离线故事)

答案 5 :(得分:0)

我认为你需要定义一个平面方法不再有效的截止点。例如,如果您在一个小型项目中有一个典型的3层架构,那么在外层有3个项目就没问题了。但是,如果您有几十个,那么某种分组有助于细分功能并使整个解决方案更容易理解。

答案 6 :(得分:0)

我更喜欢在根目录中包含项目的扁平结构。

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

在这些内部我有各种文件夹和命名空间。我只为可部署单元创建不同的程序集。小应用程序甚至不会有这么多的分离。 IMO让事情变得简单。如果我确定我需要在其他地方使用代码,只要我遵循良好的命名空间实践,只要我需要,就可以将其分解为程序集。

答案 7 :(得分:0)

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个级别