在 webforms/winforms 生成的代码场景之外,Partial Classes 有很好的用途吗?或者这个功能基本上是为了支持它?
20 回答
它部分支持将生成的代码与程序员代码混合的场景(WebForms、WinForms、LINQ-to-SQL 等)。
还有更多使用它的理由。例如,如果您在大而笨重的文件中有大类,但这些类具有逻辑相关的方法组,则部分类可能是使您的文件大小更易于管理的选项。
代码生成是部分类背后的驱动力。需求来自于拥有一个不断变化的代码生成类,但允许开发人员提供自定义代码作为类的一部分,每次进行强制重新生成的更改时都不会覆盖这些代码。
以 WinForms 或 Typed-DataSets 为例(或任何设计者)。每次您对设计器进行更改时,它都会将相应的代码序列化到文件中。假设您需要提供一些生成器不知道的附加方法。如果您将其添加到生成的文件中,您的更改将在下次生成时丢失。
我目前正在处理的一个项目使用所有 DAL、BLL 和业务实体的代码生成。然而,生成器只能得到我们 75% 的信息。其余部分必须手动编码(例如自定义业务逻辑)。我可以假设每个 BLL 类都有一个 SelectAll 方法,因此很容易生成。但是我的客户 BLL 还需要有一个 SelectAllByLocation 方法。我不能把它放在我的生成器中,因为它不是所有 BLL 类的通用。因此,我将所有类生成为部分类,然后在一个单独的文件中定义我的自定义方法。现在,当我的结构发生变化或出于某种原因需要重新生成 BLL 时,我的自定义代码不会被清除。
我使用分部类来分离我编写的自定义控件的不同子元素。此外,当与实体创建软件一起使用时,它允许像 LLBLGen 这样的产品创建类的生成版本,以及自定义的用户编辑版本,如果需要重新生成实体,则不会被替换。
我经常使用部分类来为每个嵌套类提供自己的文件。我曾研究过一些架构,其中大部分实现只需要一个类,因此我们将这些类嵌套在一个类中。通过使用部分类功能并将每个文件拆分到自己的文件中,使文件更易于维护是有意义的。
我们还使用它们对库存覆盖进行分组或隐藏一组库存属性。像这样的东西。这是一种混合库存更改的便捷方式(只需复制文件并将部分类名称更改为目标类 - 当然,只要目标类也被设为部分)。
部分类的另一个可能用途是利用部分方法通过条件编译使方法有选择地消失 - 这对于调试模式诊断代码或专门的单元测试场景非常有用。
您可以声明一种类似于抽象方法的分部方法,然后在另一个分部类中,当您键入关键字“partial”时,您可以利用 Intellisense 来创建该方法的实现。
如果您用条件构建语句包围一个部分,那么您可以轻松地切断仅调试或测试代码。在下面的示例中,在 DEBUG 模式下,调用了 LogSomethingDebugOnly 方法,但在发布版本中,就好像该方法根本不存在 - 一种使诊断代码远离生产代码的好方法,无需一堆分支或多个条件编译块。
// Main Part
public partial class Class1
{
private partial void LogSomethingDebugOnly();
public void SomeMethod()
{
LogSomethingDebugOnly();
// do the real work
}
}
// Debug Part - probably in a different file
public partial class Class1
{
#if DEBUG
private partial void LogSomethingDebugOnly()
{
// Do the logging or diagnostic work
}
#endif
}
LINQ to SQL 充分利用部分类来扩展设计器生成的代码。我认为您通常会发现设计人员创建的代码正在使用这种分部类模式。
我发现部分课程非常有帮助。通常它们用于能够扩展自动生成的类。我在一个带有大量单元测试的项目中使用了它们。我的 UT 类具有复杂的依赖关系,在多个类之间分离代码并不是很实用。当然最好使用继承\组合,但在某些情况下,部分类可能会有所帮助。
如前所述,我也认为这是代码异味。
如果一个类太大了,需要拆分成更多的文件,意味着它打破了单一职责原则,做了太多的事情。可以将大类分解为一起合作的小类。
如果您必须使用部分类或区域来组织代码,请考虑它们是否应该在自己的类中。它增加了可读性,您将获得更多的代码重用。
也许为时已晚,但请让我也加上我的 2 美分:
*.在处理大型项目时,将一个类分布在单独的文件中允许多个程序员同时处理它。
*.You can easily write your code (for extended functionality) for a VS.NET generated class. This will allow you to write the code of your own need without messing with the system generated code
在我所在的地方,我们有一个程序可以处理来自客户端的传入文件。它的设置使得每个客户端的代码都在它自己的类库项目中,它知道如何处理客户端选择使用的任何格式。
主要代码通过定义库中的类必须实现的相当广泛的接口来使用库(可能应该是几个不同的接口,但现在改变它为时已晚)。有时,在同一个类中涉及的代码比我们通常认为的谨慎得多。部分类允许我们在一定程度上分解它们。
在相对复杂的 UserControls 上,我将事件处理的东西放在一个文件中,将绘画和属性放在另一个文件中。部分类对此非常有用,通常类的这些部分是相对独立的,能够并排编辑绘画和事件处理非常好。
几年前,我参与了一个项目,我们有一个类型化的 DataSet 类,其中包含大量代码:DataTables 中的方法、TableAdapter 中的方法、TableAdapter 实例的声明等等。这是项目的一个巨大的中心点,每个人都必须经常工作,并且对部分类代码文件存在很多源代码控制争用。
所以我将代码文件分成修复或六个部分类文件,按功能分组,这样我们就可以处理较小的部分,而不必每次更改一些小东西时都锁定整个文件。
(当然,我们也可以通过不使用独占锁定源代码控制系统来解决问题,但这是另一个问题。)
一般来说,我认为这是一种代码味道。
如果您的类如此复杂,那么它可能可以分解为更小的可重用组件。
或者这意味着没有继承层次结构应该有一个。
对于代码生成场景,这很好,但我认为代码生成是另一种代码味道。
我在游戏中迟到了……但只有我的 2 美分……
一种用途可能是将现有遗留代码库中的现有神类重构为多个部分类。它可以提高代码的可发现性 - 如果包含部分类的文件名遵循正确的命名约定。这也可以减少源代码存储库 - 在一定程度上解析和合并。
理想情况下,一个上帝类应该被分解成多个小类——每个小类都有单一的职责。有时执行大中型重构会造成破坏。在这种情况下,部分课程可以提供暂时的救济。
更正,正如马特指出的那样,局部的两侧都需要在同一个组件中。我的错。
我在数据访问层中使用它。生成的类如映射器和查询部分。如果我需要添加一个映射器方法,例如执行未生成的精美加载,我将其添加到自定义类中。
最后,在业务层中使用数据层的程序员只能看到一个类具有他或她需要的所有功能。如果数据源发生变化,可以轻松生成通用部分,而无需覆盖自定义内容。
我刚刚发现部分类的用途。我有一个 [DataContract] 类,用于将数据传递给客户端。我希望客户端能够以特定方式(文本输出)显示类。所以我创建了一个部分类并覆盖了 ToString 方法。
有时您可能会发现非常旧的代码在工作,这可能使得在不破坏现有代码的情况下重构为不同的元素几乎是不可能的。
当您没有选择或时间来创建更真实的架构时,部分类可以非常容易地在需要的地方分离逻辑。这允许现有代码继续使用相同的架构,同时您更接近更具体的架构。
您之前使用过节的任何地方都#region
可能更适合作为部分类中的单独文件。
我个人将部分类用于大型类,其中静态成员放在一个文件中,而实例成员放在另一个文件中。
编辑:Visual Studio 的 DSL 工具使用部分类。
因此,它是许多自动生成的代码使用的功能。自动生成的代码不使用#region,而是转到一个文件,而用户代码(也称为自定义代码)转到另一个文件,甚至在不同的目录中,这样开发人员就不会对这么多无意义的文件感到困惑。
有这个选项很好,你可以结合 - 但不强制使用 - 与继承
此外,将某些类的逻辑分离到几个目录中也很方便。当然,对于机器来说,也是如此,但它增强了用户的可读性体验。