Bor*_*ode 6 c# namespaces circular-dependency circular-reference
在c#中,您可以在文件a.cs中具有语句(其具有MyApp.A的命名空间):
using MyApp.B;
Run Code Online (Sandbox Code Playgroud)
而文件b.cs(具有MyApp.B的命名空间)已经有了该语句
using MyApp.A;
Run Code Online (Sandbox Code Playgroud)
如果在不同的dll中存在类似的依赖关系(其中a.dll具有对b.dll的引用,反之亦然),由于循环依赖性错误,它将不被允许,所以为什么它允许使用命名空间(并且编译器不允许)甚至产生警告)?无论如何,这不是代码味道吗?
Damien_The_Unknowner写道,命名空间是功能的逻辑分组。
Hans Passat写道,命名空间只不过是对编译器的一个简单提示。
我想详细说明一下,这实际上取决于您认为代码库中的组件是什么。组件是一组类型。一个组件可以生成一个或多个程序集中定义的一个或多个命名空间。重要的是组件之间不存在依赖循环。因为组件是一个开发单元,如果A组件和B组件互相使用,就构成了一个更大的开发单元,它们就不能独立开发,形成一个超级组件,或者说,这就是根意大利面条代码。
回答你的问题,为什么 C# 中的命名空间允许循环依赖?您的问题背后的隐式声明是名称空间用于定义逻辑组件。但是命名空间也可以用来避免类型名称冲突,以结构化的方式呈现公共 API 的类,过滤一组扩展方法......因此我猜答案是C# 设计者当然不想限制命名空间的概念仅用于逻辑组件化。
附带说明一下,许多开发人员正在使用项目/装配的概念来定义组件。恕我直言,这是错误的,因为组装是一个物理概念,伴随着成本和维护(版本控制、部署、编译、动态 CLR 加载...)。装配作为物理概念应该出于物理原因而使用(例如部署单元、API 单元、插件实现、代码/测试分离...)。如果您感兴趣的话,我写了两本关于程序集、命名空间和组件主题的白皮书。
无论如何,这样做不是有代码味道吗?
在我看来是的,因为如果一个大型程序集包含许多具有依赖循环的命名空间,那么人们就无法尝试从代码中理解整体架构。我正在开发一个名为 NDepend 的 .NET 静态分析器,它可以检查命名空间依赖循环并通过依赖图和依赖矩阵呈现结果。我们有 400 多个命名空间,我们很高兴将它们全部正确地分层在十几个程序集中。依赖矩阵提供了一种方便的方法来一目了然地可视化分层命名空间结构。