【问题标题】:Pitfalls of creating extensions to the .net System libraries inside the System namespace在 System 命名空间内为 .net System 库创建扩展的陷阱
【发布时间】:2012-05-15 13:14:30
【问题描述】:

在我工作过的所有公司中,我最终都拥护一组核心库,这些库除了增强和扩展 .net 库外无济于事。通常我的命名空间以我们的公司名称开头,但子命名空间反映了System 命名空间的名称。

Foo.IO; Foo.Web

我打算更进一步,将 company 命名空间替换为 system 命名空间,这样您只需要一个 using 语句,从而更好地增强核心库。

namespace System.IO
{
    public static class StreamExtensions
    {
        ...
    }
}

实际问题

现在我知道这是可能的,微软在他们自己的库中做到了,我已经看到在其他第三方库中做到了,但我想知道的是,如果有的话,这样做的长期影响是什么作为.net 更高版本中的类名冲突?有没有人这样做并且不得不处理一个复杂的问题,破坏了仅仅能够添加程序集引用的简单性?

更新

不幸的是,这已经变成了关于你是否应该这样做的更多辩论,这可能属于程序员。不雅地还有另一个SO question 确实问过这个问题,但这不是问题的重点。

我想知道是否存在会导致编译错误或奇怪行为的场景。唯一出现的两个论点是。

  1. Microsoft 将方法添加到与库中扩展方法的签名相匹配的对象,但这是一个静音点,因为它不会影响扩展方法所在的命名空间,因为对象上的实现会优先。

  2. 其他人在他们的第三方库中做了同样的事情,我们有一个名字冲突。这更有可能是我们已经必须处理的问题,第三方库 ILM 将其他库合并到它们的程序集中。

需要说明的是,这是一个独立的库,它是供内部使用的,不能在外部使用,并且可以通过扩展方法扩展现有的系统库。

【问题讨论】:

  • 如果您这样做的唯一原因是不必包含额外的命名空间,那么我建议您不要这样做。
  • @Nick 感谢您的评论,但基于什么理由?这是一个有效的陈述,但问题是什么意思。包括我自己在内的其他人都回避了这样做,因为对弄乱别人的命名空间有一种“直觉”的感觉,但没有人因此而说不要这样做。如果您有具体的事实原因,我很想听听。
  • 我想这主要是因为“直觉”感觉它是错误的。好问题!
  • 除了坚信命名空间应该与它定义的 dll 有一些模糊的相似之处。如果你与其他代码库合并会发生什么,他们做了类似的事情?命名空间旨在隔离代码,以避免您计划创建的混乱。
  • 我自己实际上已经在自己的扩展库中使用了这种技术,我认为这样做并没有什么坏处。原因是您在技术上不是通过使用扩展“添加”到命名空间。您只是在某些类型上扩展功能。通过将其包含在我们公司的一个基础项目中,所有这些扩展方法都可供其他开发人员发现和使用,而无需包含额外的参考。至于这是否是一个糟糕的设计决定:这完全取决于你。确保您有唯一的名称并且不应该存在类冲突。

标签: c# .net namespaces


【解决方案1】:

我建议不要这样做。 System 命名空间是 .NET Framework 命名空间,如果您想从该命名空间自定义类,请在代码中明确说明。

这意味着使自定义类成为您自定义命名空间的一部分。

别把事情搞砸了。

【讨论】:

  • 我很欣赏这是您的意见,但基于什么理由。什么是“技术”影响?
  • 负面影响不仅是技术上的(除了弄乱命名空间外,我看不到太多技术影响)。 imo 这样做的坏处不是技术上的负面影响,而是可读性差,因此可维护性影响。
  • 没错,但谈话的另一半属于程序员。这不是为了引发一场辩论,我想要一个“如果你这样做,那么这个特定的坏事可能会咬你”,或者“不,一切都很酷”。
  • @Bronumski:好的,所以我的回答是:不,这是一个糟糕的设计,不要这样做,原因如上所述。
  • 我原来的评论仍然有效,你没有给出理由只是一个建议。我正在寻找技术原因或引起疼痛的场景,以验证您的立场,即这是一个糟糕的设计。重要的是,当其他人查看我们的问题和答案时,他们完全理解其背后的思考过程。
【解决方案2】:

这可能有点离题,但参考您提到的替代方法:

通常我的命名空间以我们的公司名称开头,但子命名空间反映了系统命名空间的命名空间。

我在使用这种方法时遇到了一些问题。

我的公司名称是 Resolv - 因此,我写的很多东西最终都会以 Resolv. 的形式进入命名空间(其余的将是 .)。

我开始在名为 Resolv.System 的命名空间中构建我的扩展方法、静态类等库

但是,当使用以 System 开头的“完全限定”类型名称(例如 var myVar = new System.Collections.List<int>();)时,会产生命名空间解析问题。

虽然在这种特殊情况下我永远不会使用完全限定名称,但如果我引用的类型是整个代码文件中该名称空间中唯一的类型(在这种情况下添加 @987654322 @ 没有保证) - 或者在导入的两个命名空间(使用 using 语句)包含冲突的类型名称的情况下。当没有合适的 using 语句时,自动代码生成工具(如 resharper)通常会添加此类引用。

如果我在 Resolv 内的某个命名空间 anywhere 中处理代码(例如 Resolv.MyInternalProject) - 我输入的 应该 是一个完全限定的名称 - 混淆由于 Resolv.System 命名空间而发生。编译器返回当前命名空间,到达 Resolv,然后找到 Resolv.System。这意味着 - 例如 - new System.Collections.List<int>() 将尝试使用不存在的类 Resolv.System.Collections.List<int>()。

当然,我可以通过使用 var myVar = new global::System.Collections.List<int>() 的形式来解决这个问题,但这很丑而且有点痛苦)。

我选择在我的扩展命名空间树中包含一个“项目名称”,所以现在我有Resolv.Extensions.System 而不是Resolv.System。从那里子命名空间镜像系统命名空间(例如Resolv.Extensions.System.IO)。这样我就可以更好地控制我是否想让 System.xxx.xxxx 引用引用我的扩展名,或者任何给定代码文件中的 .net 引用(并且它只是一个 using 语句,可以在我想要的时候添加到我的代码文件中“打开扩展”)。

当然,在处理 Resolv.Extensions 命名空间内的代码时,我仍然会遇到 System.xxx.xxx 命名空间混乱 - 但这不会让我每天都感到烦恼! :)

【讨论】:

    【解决方案3】:

    我打算做的是更进一步,更换 company 命名空间与系统命名空间,这样你只需要 有一个 using 语句,因此可以更好地增强 核心库。

    我不明白这将如何增强核心库。当 Microsoft 将相同的方法添加到 String 类并执行完全不同的操作时会发生什么?这就是他们应该在自己的命名空间中的原因。

    现在我知道这是可能的,微软自己做 图书馆,我已经在其他第三方图书馆看到过它,但是 我想知道的是,如果有的话,长期影响是什么? 这样做诸如在更高版本的 .net 中出现类名冲突?

    长期影响是,如果 Microsoft 将与您创建的扩展方法相同的方法添加到类中。

    有没有人这样做并且不得不处理已损坏的并发症 只是能够添加程序集引用的简单性?

    我不明白您要减少引用数量的原因。这样做你什么也得不到,在它们自己的命名空间和类中拥有实用程序方法是一个有效的设计决策,人们认为它们将是独立的,而不是 Microsoft 命名空间的一部分。

    这是一个有效的陈述,但问题是什么是 影响。其他人,包括我自己,都避而远之 这样做是因为对与某人搞砸的“直觉”感觉 else 的命名空间,但没有人说不要因为这个而这样做。如果 你有一个具体的事实原因,我很想听听。

    这意味着开发人员假设 System 命名空间仅填充了 Microsoft 代码。

    【讨论】:

    • “长期影响是,如果 Microsoft 将与您创建的扩展方法相同的方法添加到类中。”与 Extension 方法位于另一个命名空间中没有什么不同。无论扩展方法位于哪个命名空间,对象上的方法都优先于扩展方法。
    • @Bronumski - 我建议不要使用扩展方法,而是让它们完全分开有实用方法。
    • 那么您是不是提倡对 System 命名空间中的对象完全不使用扩展方法?
    猜你喜欢
    • 2012-10-30
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多