C#中的局部类
在Webforms / winforms生成的代码方案之外,局部类是否有很好的用途?还是此功能基本上可以支持该功能?
解决方案
LINQ to SQL很好地利用了部分类来扩展设计人员生成的代码。我认为我们通常会发现这种由设计师创建的代码使用的部分类模式。
我在哪里,我们有一个程序来处理来自客户端的传入文件。设置它的目的是使每个客户端的代码都在自己的类库项目中,该项目知道如何处理客户端选择使用的任何格式。
主代码通过定义库中的类必须实现的相当广泛的接口来使用库(可能应该是几个不同的接口,但是现在更改它为时已晚)。有时在同一个类中涉及的代码要比我们通常认为谨慎的多。局部类使我们可以对它们进行一些分解。
它部分是为了支持将生成的代码与程序员代码混合在一起的方案(WebForms,WinForms,LINQ-to-SQL等)。
有更多使用它的理由。例如,如果我们在大型笨拙的文件中有大型类,但这些类具有逻辑相关的方法组,则可以使用部分类来提高文件大小的可管理性。
我使用部分类作为分离我编写的自定义控件的不同子元素的方法。此外,当与实体创建软件一起使用时,它允许LLBLGen之类的产品创建类的生成版本以及用户定义的自定义版本,如果需要重新生成实体,则不会替换它们。
我发现局部类非常有帮助。通常,它们用于扩展自动生成的类。我在一个具有大量单元测试的项目中使用了它们。我的UT类具有复杂的依赖关系,将代码跨多个类分开并不是很实际,当然最好使用继承\组合,但在某些情况下部分类可能会有所帮助。
在相对复杂的UserControls上,我将事件处理内容放在一个文件中,并将绘画和属性放在另一个文件中。局部类对此非常有用。通常,这些类的这些部分是相对独立的,能够并排编辑绘画和事件处理非常好。
正如Matt所指出的那样,校正必须在同一装配体中同时进行。
我的错。
我在数据访问层中使用它。生成的类(例如映射器)和查询局部类。例如,如果需要添加一个映射器方法来执行未生成的奇特负载,则可以将其添加到自定义类中。
最后,在业务层中使用数据层的程序员只能看到具有所需功能的一类。而且,如果数据源发生更改,则可以轻松生成通用部分,而无需覆盖自定义内容。
我只是发现了局部类的用途。我有一个[DataContract]类,用于将数据传递给客户端。我希望客户端能够以特定方式显示类(文本输出)。所以我创建了一个局部类并覆盖了ToString方法。
我经常使用部分类为每个嵌套类提供自己的文件。我曾经研究过一些体系结构,其中大多数实现只需要一个类,因此我们将这些类嵌套在一个类中。通过使用部分类功能并将每个文件拆分为自己的文件,可以使文件维护更容易。
我们还将它们用于对股票替代项进行分组或者隐藏一组股票属性。像这样的东西。这是混合库存变更的便捷方法(当然,只要将目标类别也设为局部类别,只需复制文件并将局部类别名称更改为目标类别即可)。
代码生成是部分类背后的驱动力。需求来自不断变化的代码生成类,但允许开发人员提供自定义代码作为该类的一部分,每次进行强制生成该类的更改时,自定义代码都不会被覆盖。
以WinForms或者Typed-DataSets为例(或者与此有关的任何设计器)。每次更改设计器时,它都会将相应的代码序列化到文件中。假设我们需要提供一些生成器不知道的其他方法。如果将其添加到生成的文件中,则更改将在下次生成时丢失。
我当前正在从事的项目为所有DAL,BLL和业务实体使用代码生成。但是,生成器仅获得我们75%的信息。其余部分必须手工编码(例如,自定义业务逻辑)。我可以假设每个BLL类都有一个SelectAll方法,因此很容易生成。但是,我的客户BLL还需要具有SelectAllByLocation方法。我不能将其放在生成器中,因为它不是所有BLL类都通用的。因此,我将所有类生成为部分类,然后在一个单独的文件中定义我的自定义方法。现在,当我的结构发生变化时,或者由于某种原因需要重新生成BLL时,我的自定义代码将不会消失。
有时,我们可能会在工作中发现非常古老的代码,这使得在不破坏现有代码的情况下将其重构为不同的元素几乎是不可能的。
如果没有选择权或者没有时间去创建更真实的体系结构,则局部类将使在需要时分离逻辑的工作变得异常容易。这使现有代码可以继续使用相同的体系结构,同时又可以更接近于更具体的体系结构。
几年前,我在一个项目上工作,其中有一个类型化的DataSet类,其中包含大量代码:DataTables中的方法,TableAdapters中的方法,TableAdapter实例的声明,都可以为它命名。这是每个人都必须经常进行的项目的重要中心点,并且在部分类代码文件上存在许多源代码控制争用。
因此,我按功能将代码文件分为固定文件或者六个部分类文件,然后按功能分组,这样我们就可以处理较小的文件,而不必每次更改某些小东西时都锁定整个文件。
(当然,我们也可以通过不使用排他锁定的源代码控制系统来解决该问题,但这是另一个问题。)
在局部类中作为单独文件使用之前,可能在使用过#region部分的任何地方都更有意义。
我个人将部分类用于大型类,其中静态成员位于一个文件中,而实例成员位于另一个文件中。
通常,我认为它是一种代码气味。
如果课程如此复杂,则可以将其分解为较小的可重用组件。
或者意味着没有继承层次结构,应该有一个继承层次结构。
对于代码生成方案来说,这很好,但是我认为代码生成是另一种代码味道。
编辑:用于Visual Studio的DSL工具使用部分类。
因此,这是许多自动生成的代码使用的功能。
代替使用#region,自动生成的代码转到一个文件,而用户代码(也称为自定义代码)转到另一个文件,甚至在不同的目录中,这样开发人员就不会与这么多毫无意义的文件混淆。
可以组合但不强制使用-with继承的选择是一件好事
同样,在一些目录中分离某些类的逻辑也很方便。当然,对于机器来说,是相同的,但是它增强了用户的可读性体验。
如前所述,我也认为这是一种代码味道。
如果一个类太大而需要将其拆分成更多文件,则意味着它正在打破单一职责原则,并且要做太多事情。
可以将大类分解为相互合作的小类。
如果必须使用部分类或者区域来组织代码,请考虑它们是否应属于自己的类。它提高了可读性,并且我们将获得更多的代码重用。
局部类的另一种可能用途是利用局部方法,使条件条件下的方法有选择地消失,这对于调试模式诊断代码或者特殊的单元测试场景将非常有用。
我们可以声明一种类似于抽象方法的局部方法,然后在另一个局部类中,当我们键入关键字" 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 }