推荐的方法来防止 C# 中的助手类造成命名污染?
Posted
技术标签:
【中文标题】推荐的方法来防止 C# 中的助手类造成命名污染?【英文标题】:Recommended way to prevent naming pollution by helper classes in C#? 【发布时间】:2016-01-17 15:10:10 【问题描述】:我经常遇到这样的模式:我有一个主类和几个较小的辅助类或结构。
我希望这些结构的名称尽可能简洁。因此,当我有一个名为CarFinder
的类大量使用某些仅(或主要)在内部使用的特殊 Key 对象时,我想将该对象称为Key
而不是CarFinderKey
。
一切都消除了所有额外的模糊,当我在阅读时尝试理解课程时会分散我的注意力。
当然,我不想用一个名为 Key
的小帮助程序类来污染其余代码 - 它很可能会发生冲突和混淆。
在一个完美的世界中,我希望有一个像 internal to this namespace
这样的关键字,但由于它不存在,所以我可以想到以下选项:
-
使用
internal
并将该类放在不同的项目中。
优点:完美封装。
缺点:大量的组织开销和不必要的复杂依赖。
注意:我不是在谈论真正值得自己组装的大型独立系统。
-
将其放在不同的子命名空间中,例如
CarFinding.Internal
优点:易于实施。
缺点:意外导入命名空间时仍然会造成污染。
-
将帮助类作为子类放入
CarFinder
。
优点 不会对内部造成污染,甚至可以提升为公共辅助结构体,以CarFinder.Key
向外部世界公开
缺点 必须将辅助类放在同一个文件中,或者将其封装在一个外部文件中,并在其周围加上public partial class
。第一个使文件变得不必要的长,第二个感觉真的很难看。
-
随便叫
CarFinderKey
优势易于实施。
缺点 在我看来,CarFinder
添加了太多fuzz。仍然不必要地污染命名,只是用一个不太可能发生冲突的名称。
推荐的准则是什么?
【问题讨论】:
这个问题的本质对于SO来说太抽象和基于意见。您最好在 SE Programmers (programmers.stackexchange.com) 之类的网站上发布此类问题。 我总是使用内部或私有嵌套类(你在 3. 中称之为子类)。 .NET 框架本身大量使用这种模式(甚至在内部用于 C# 语法糖、产量等)。它们还有一个你没有列出的很大优势:它们可以访问包含类的私有成员和受保护成员。 能否详细介绍一下“Key”类的字段和操作?如果操作可以抽象为系统中的所有实体使用,则只需实现系统范围的 EntityKey您的决定应取决于您的设计。您的 Key 类真的是只适用于 CarFinders 的钥匙吗,或者它也可以用于查找摩托车或房屋或其他任何东西。
著名的四人帮制定的第一条规则是“为改变而设计”。如果您真的认为在不久的将来您的钥匙也可以用来寻找房屋或摩托车,那么将您的钥匙类设为私有以使其他人无法使用它不是一个好主意。
由于您说的是私有助手类,我假设您的密钥仅对 CarFinders 有用。
如果是这种情况,并且您的设计规定 Key 仅对 CarFinders 有用,或者甚至:如果它的设计使其在 CarFinders 之外甚至没有用,则 Key 类应该是 CarFinders 类的一部分.将此与您将在 CarFinders 类中使用的简单整数进行比较,您会在 CarFinders 类中将其声明为私有,不是吗?
给您留下一个大文件或部分定义的问题。从设计的角度来看没有区别。对于编译器来说也没有区别。唯一的区别是对于必须阅读它的人。如果您认为您的类的用户很少需要阅读您的关键类的定义,那么最好在单独的文件中定义它。但是,如果您在阅读 CarFinder 课程时经常需要阅读钥匙课程,您应该尽可能轻松地访问钥匙课程。如果您的开发环境是面向文件而不是面向类的,那么我认为在这种情况下,大文件的缺点小于必须在文件之间切换的缺点。
【讨论】:
【参考方案2】:我多次遇到同样的困境,并且个人使用 (3) 和 (4) 的变体。
(3): 我既不将嵌套类/结构放在同一个文件中(如果它很小并且确实与父类绑定),也不在partial ParentClass
声明中使用单独的文件 - 唯一缺点是它获得了更高级别的缩进,但我可以忍受。我也没有违反 FxCop 规则或其他建议的问题 - 毕竟,它们只是建议,不是强制性的。但是很多人确实对所有这些或部分问题都有疑问,所以让我们继续吧。
(4): 你已经描述了缺点。我要分享的是我如何克服它们。同样,它是个人的,可能会或可能不喜欢它,但它就是这样。
首先,假设我们为密钥类使用单独的文件并将类命名为CarFinderKey
。
然后,在CarFinder
类的代码文件中,我们将以下行放在using
部分的末尾(或任何内部):
using Key = CarFinderKey;
这样,只在 CarFinder
类代码文件中,任何需要CarFinderKey
的地方,我们都可以简单地将其称为Key
,目标是什么。同时,我们保留了所有优势,没有冲突。智能工作没有任何问题。在 VS2015 中,灯泡甚至会建议在该文件中找到 CarFinderKey
的任何位置为您“简化名称”。
【讨论】:
赞成,但我不喜欢这样的事情使用别名。命名空间消歧的别名(我的很多文件系统文件中的using _File = Pri.LongPath.File
)而不是名称缩短。
@Corey 当然,我也明白反正没有多少人会喜欢它。我认为这更像是代码统一而不是缩短。就我而言,我有很多类似的相关类集,例如 entity, dto, repository etc. 所以我更喜欢将它们(在大多数情况下)视为通用类参数(尽管它们不是),并且通常创建“标准”别名using TEntity = ...; using TDto = ...; using TRepository = ...
。但这只是个人喜好(无论如何都是原始问题:-))
我曾经这样做,但现在我将其限制为缩短极长的通用本地类,或者我使用库中的类来模仿各种 System.IO 替换等框架类。我只是认为这有助于消除歧义。我尽量避免在程序集中有多个类在不同的上下文中具有相同的名称,这只会导致更多的混乱......而且我已经足够了:)【参考方案3】:
这是基于意见的。无论如何,我会:
尝试使其成为CarFinder
的私有嵌套类,这通常会失败,因为Key
需要传递给CarManager
,你知道我的意思。不鼓励使用公共嵌套类。
我会将其放入名为Core
的子命名空间中,这是内部内容的通用名称。对我来说,Core
按照命名约定是“内部命名空间”。
项目越大,您需要的名称就越长。 CarFinderKey
仍然是一个有效的选项。
我永远不会为此创建额外的程序集。就是感觉不对。
【讨论】:
感谢您详细解释的答案。是否有明确的理由不鼓励公共嵌套类? 有一条 FxCop 规则符合这一点:msdn.microsoft.com/en-us/library/ms182162.aspx @DirkBoer 如果您有一个公共嵌套类,并且它嵌套的唯一原因是提供一些语义分离,那么如果您考虑一下,您就是在使用“外部”类(您将其嵌套在其中的那个)作为嵌套类的命名空间。在这种情况下,我认为只使用命名空间是更好的做法。【参考方案4】:就我个人而言,我不介意 CarFinderKey 造成的额外“模糊”,原因如下:曾经参与过一个非常大的项目,我们尝试使用命名空间来消除名称的歧义。
因此,当您扩展系统时,您可以很容易地在代码编辑器中打开 10 个选项卡,全部命名为“Key.cs”。那真的不好玩。
【讨论】:
完全同意这一点。你永远不知道一个项目什么时候会成长或改变,完全明确的名称会有所帮助。如果涉及数据库,尽量避免使用 SQL 关键字也是不错的选择。【参考方案5】:我会把这个类和他们的“助手”放在他们自己的命名空间MyNamespace.CarFinding,
这样你就有了:
MyNamespace.CarFinding.CarFinder
MyNamespace.CarFinding.Key
我将把这个命名空间放在项目的子文件夹中。
这不会阻止在项目的其他地方使用内部帮助程序类,但您可以从父命名空间将您的帮助程序引用为 CarFinding.Key
【讨论】:
这意味着所有使用CarFinder
的类都被一个名为Key
的类所污染——这正是我试图防止的。
如果你总是显式引用具有命名空间的类,例如 CarFinding.CarFinder 和 CarFinding.Key,而不添加 using 指令,则不会。
或者您可以仅为助手创建一个名称空间,例如 CarFinding.Helpers.Key,这样您只需使用 Helpers 名称空间污染名称空间,您只需在 CarFinder 中将该类作为 Key 引用,然后如果你想在外面使用它,你可以使用完整的 CarFinding.Helpers.Key。
我喜欢流畅的接口,它让我能够将所有帮助类放在完全不同的命名空间中,我唯一看到它们的时候是我正在处理的当前类或方法引用项目其他地方的扩展方法。例如,所有类都可能有 ToString() 方法,但它们没有 ToXMLString() 方法。我可以简单地创建一个仅用于这个或一组特定类的扩展方法。中提琴!没有命名空间污染,但在您需要时会提供帮助。以上是关于推荐的方法来防止 C# 中的助手类造成命名污染?的主要内容,如果未能解决你的问题,请参考以下文章