程序集...内部和外部命名空间

Posted

技术标签:

【中文标题】程序集...内部和外部命名空间【英文标题】:Assembly ... internal & external namespacing 【发布时间】:2013-12-18 01:08:45 【问题描述】:

在这里有一个简单的问题。我有一个程序集被一些开发人员重用,其中包含各种功能,但在技术上被拆分为表示功能逻辑块的各种命名空间。

现在,它提供了尽可能少的公共命名空间。基本上,用户不应该知道(目前也不知道)他们尝试使用的类正在使用哪个内部结构。

假设你有这个:

NS1

NS11 111 班 112 级 NS 扩展 扩展类 1 NS12

NS2

...

基本上,用户知道他们使用 FrameworkName.NS1 来实现有关 NS1 的一般功能。 现在,在这个简单的示例中,我将一个包含扩展方法的类放在子命名空间扩展中,所以基本上,如果最终用户尝试使用程序集,他必须实际知道 DLL 的内部结构才能知道扩展存在(这是智能感知不会告诉你你知道的例子之一)。

所以底线......现在我已经有了这个程序集,并且在内部(VS 项目)我像往常一样将项目划分为逻辑文件夹,但我不让命名空间跟随文件夹。这样,程序集就被拆分成逻辑块,用户知道这些逻辑块而不必知道内部结构,也不需要知道可能存在用于扩展的单独命名空间等。

现在,我个人希望我可以让代码的命名空间遵循我的文件夹结构,但在编译时以某种方式将这些子命名空间映射到主命名空间。

是否有可能以某种方式实现这种“重定向”?

简而言之,我希望能够在程序集外部将 NS1.NS11.Class111 公开寻址为 NS1.Class111,同时仍保持程序集内部的正确结构。

【问题讨论】:

有趣的问题。一种类型只能存在于一个命名空间中。如果您在(预)编译时将 NS1.NS11.Class111 更改为 NS1.Class111,您还必须更改对它的所有引用,因为现有(测试)代码将期望它位于 NS1.NS11 中。 我个人的想法是,你为什么不在内部使用与外部相同的命名空间?如果他们让外部人员感到困惑,那么为什么不让内部人员感到困惑? 这并不是因为它们令人困惑。只是最终用户不必知道内部结构就能完成他们的任务。假设您在内部有一个实用程序命名空间,其中包含例如“加密器”类,但您希望您的用户可以访问您的所有实用程序,而不必知道它被视为程序集中的实用程序。 该死,cmets 太矮了。 :-) 对于扩展类和自定义异常类也是如此,您希望最终用户能够访问 DLL 中可用的类,而无需手动记住每次都添加自定义内部 .extensions 命名空间,但一切都只需导入基础命名空间。 一个坏主意。代码应仅位于 1 个命名空间中,因此只需做出选择。当您不想遵循文件夹结构(只是一个明智的 VS 默认设置)时,请不要使用它。但不要在编译(发布)时更改它。那会破坏很多东西。 【参考方案1】:

如果您需要通过不同的命名空间提供对某些内部代码的第三方访问,我会将数据访问抽象到单独的程序集(取决于原始程序集)中,或者使用 Web 服务来提供子集您希望他们访问的功能。

您也许可以对每个类的属性做一些事情,尽管我想它会很快变得非常混乱。

【讨论】:

【参考方案2】:

有几种方法可以考虑这一点。 最初来自 VB.net 背景和最近的 C#,我有以下关于该主题的 cmets。

    VB 不采用文件夹\命名空间约定。 您将如何解决代码版本控制和管理问题。 如果引入其他 c# 开发人员来补充您的团队,他们可能会发现很难理解命名空间/文件夹转移。 您可以将父命名空间放在 csproj 属性中,在应用程序“默认命名空间”下。这将允许您通过复制和粘贴继承或源代码管理文件夹或子项目在项目之间共享这些通用实用程序(文件夹)。这允许 NS1.Extensions 和 NS2.Extensions 包含相同的代码。 我不会担心过多地“隐藏”内部企业 API,除非它是一个特别恶劣的技术环境。甚至您的“加密”方法也应使用适当的公钥/私钥基础设施来确保其设计安全。 如果您查看大多数框架如何分解那里的解决方案,您会看到一系列项目,其中包括“Core”、“Shared”、“Common”等命名空间的所有代码。这些开发人员中的大多数都非常聪明,所以如果这是他们做事的方式,我会效仿。 您是否考虑过将 nugget 部署到“共享网络文件夹”并设置所有开发人员将 VS 指向该位置? 最后我发现扩展和辅助方法很快就变得非常稳定,所以代码没有太大变化。我将它们推送到包含在我的源代码管理/library/MyBusinessName/NameOfService.1.0.0.0/ 中的文件夹中。与 Nuget 包使用的文件夹结构相同,因此我知道何时使用我的核心底层公司代码或框架的版本。 最后,如果你要让你的代码沿着MVVM 路径(流行)向下移动并且你看到dependency injection 中的值,那么你将不得不包含很多“接口”来帮助测试你的共同点共享代码,这在单独的 DLL/项目中要容易得多。

就我个人而言,我曾与一个团队合作,该团队为他们在公司软件中引用的每一件事导入了所有底层源代码,因此他们可以“改变”任何东西。归根结底,它创造了一个邪恶的构建复杂性水平,并在调试时吓坏了我。 Nuget 提供了一种很棒且非常流行的模型,我已将其用于企业“共享”代码。如果我需要“tweek”共享代码,我会在解决方案/项目中单独进行,对其进行测试、部署并使用源代码控制或 nugget 复制文件。

【讨论】:

【参考方案3】:

这是一个想法:创建包装类供公众使用。它可能有点低效(尽管 JIT 可能会处理它)并且相对更难以维护,但是如果您担心公共 API(应该如此),它可能是一个不错的选择。在大多数情况下,链接几个调用不会有任何问题,并且您将有一个与公共 API 相关的层,这可能允许您在外观背后犯一些罪(为了以性能为例)

您可以随意创建内部结构:

namespace Framework.Cool.Internal

    internal class BeansWeWantToCook
    
        internal bool Cook()
        
            // cooking process
        
    

..然后使用您要公开的命名空间为内部功能创建一个公共包装器:

namespace Framework.Cool

    public class Beans
    
        // omitted code for brevity
        public bool Cook()
        
            return _beansWeWantToCook.Cook();
        
    

这将创建一个非常传统的结构,不会让任何正在寻找浏览您应用程序的类的人感到惊讶。

另一种选择是采用特定于项目的约定,例如将所有公共类保留在项目的根目录中。

顺便说一句,我不会对编译或构建时间过程做任何有趣的事情。我认为这太令人困惑了,尤其是对于新来的人。

【讨论】:

以上是关于程序集...内部和外部命名空间的主要内容,如果未能解决你的问题,请参考以下文章

封装 继承

面向对象思想

面向对象思想

面向对象:封装继承

“使用”应该在命名空间内部还是外部? [复制]

面向对象 封装 集成 特性