为什么要使用局部类?


72

以我的理解,该partial关键字什么也没有做,只是允许在几个源文件之间拆分一个类。除了代码组织之外,还有其他理由吗?我已经在生成的UI类中看到了它的用法。

似乎没有理由创建整个关键字。如果一个类足够大而需要多个文件,那么它可能做得太多。我以为您也许可以用它部分地定义一个类,供其他程序员在某个地方完成,但是最好创建一个抽象类。


10
它也不是一个“整体关键字”。这是一个上下文关键字partial只有在出现时才有意义class。您可以使用它作为代码等其他地区的标识符名称
迪恩·史密斯

4
如果您使用它们,而不是用于生成的代码,那么我恨您。不是您本人,而是您一般。我讨厌通过局部类来查找代码。
史蒂文·埃弗斯

3
“查找代码”并不难,所有类方法仍然显示在VS的下拉列表中,无论您正在查看部分代码的哪一部分。其他代码导航也可以正常工作(“聪明的” R#样式导航或良好的旧shift-ctrl-f
Steve,

2
误将部分类放在单独的文件中是一种误解。
巴特

Answers:


110

在每种情况下某个自定义工具生成类的一部分的每种情况下,它都非常有用,因为它允许您在不继承生成的类的情况下向生成的代码添加自定义逻辑。顺便说一句。出于相同的原因,也有部分方法。

它不仅与UI有关,而且其他技术(如Linq-To-Sql或Entity Framework)也大量使用此功能。


44
同样,它使您可以将代码保持在版本控制之下,同时将生成的代码置于版本控制之外。
Frank Shearar 2011年

3
好点,我从来没有想过。我只看到它在实践中被滥用。(糟糕的)程序员使文件大小易于管理的一种方法。
Martin Wickman

1
我使用过的最好的例子是:a)在想要扩展类的Linq to SQL数据上下文中;b)扩展从Web服务传递的类。在两种情况下是这样的滥用,也不是为了使文件大小的管理手段......我会从根本上不愿意看到它以这种方式使用(并会采取措施...)
墨菲

3
WinForm类使用它来隐藏所有设计器代码创建控件(特别重要,因为设计器喜欢对重新创建的所有代码进行随机重新排序,从而在diff / blaming时造成巨大的混乱),并且如果您使用的是XML,则XSD工具可以再次从模式文件创建部分类,使您可以将代码与自动生成的排序分开。
Dan Neely

2
@MartinWickman不一定很烂。这是在遗留代码中重构God对象的良好起点。尝试通过先将大类拆分为单独的文件来清理环境。(我知道您的评论很老)
Konrad Morawski 2014年

26

如您所说,它通常用于分隔生成的代码。它通常与类/文件的大小无关。

分离生成的代码的好处是样式之一。生成的代码非常丑陋且不可读,并且会导致许多编码标准(以及StyleCop检查)无法通过,但这没关系,没有人必须阅读或直接维护它。因此,如果您将其“隐藏”在另一个文件中,则可以集中精力确保该类的其余部分符合标准,并通过StyleCop检查等等。

我用过的另一个地方是一个类实现多个接口,将实现分离到单独的文件中会很好,尽管这更多是个人喜好,我从未见过任何编码标准要求(或防止)。


9
我从来没有想过使用类局部函数来分离接口实现,这是一个好主意。
Mark Booth,

它不仅仅是样式。代码生成器的开发人员将不得不跳过箍以允许您编辑由生成器管理的文件中的代码,即使那样也将是有问题的。对我来说,第一大好处是给您一个编写生成器将/无法触摸的代码的地方。这是一个明显的好处。
丹尼尔(Daniel)

19

我工作的一位开发人员在几周前提出了对他们很好的用处,以重构庞大的God类,这些类逐渐失去控制并具有许多公共方法:通过分离每部分的逻辑功能将该类划分为单独的部分类,您可以在不破坏任何现有功能的情况下,将类物理上划分为应该是该类的更多原子单元,从而使您可以看到什么是通用的,什么不是通用的。以此为第一步,您可以更轻松地将部分分解为各自的独立类,并在整个代码库中实现它们。我认为这是一个好主意。

但是,总的来说,我认为仅在编写新代码时才应使用它们来扩展机器生成的类。


1
我可以看到这很方便。这是否是用语言来证明的理由...我不知道。不过,机器生成的代码是另外一个故事。
Michael K

2
是的,使用该语言并不是正当的理由,但这是使用它们的一种有趣方式。

18

我可以想到一些有用的场景,其中的局部是有意义的,其中大多数是我在项目中使用的自己:

  • Tool / IDE / Designer生成的代码与您要维护的代码分开。一个很好的例子是该Form.Designer.cs文件包含设计器为Windows窗体应用程序生成的代码。许多其他.NET格式还具有一些由工具生成的代码,可以在生成项目时重新生成这些代码,因此所有自定义更改都将被清除。分离将帮助您保持代码和更改免受此类自动修改的影响。

  • 当您在实现中使用大量代码实现多个接口时。我倾向于使用一个单独的部分文件对于每个这样的接口,将其命名为这样的:{Class}.{Interface}.cs。我很容易在IDE中看到{Class}正在实现的接口和实现方式。

  • 当类必须包含一个或多个嵌套类时,尤其是其中包含足够的代码才能放入单独的文件中时。我会坚持上述模式,并{Class}.{NestedClass}.cs为每个嵌套类使用命名约定。Virtlink的答案已经提到了类似的做法。

  • 当我编写static将包含扩展方法的类时。通常会为相似的类或接口提供相同的扩展方法逻辑,例如Reverse在通用和非通用集合上。我会将单个类或接口的所有扩展方法放在静态类的单独部分中。例如,我将IList在一个位置具有该接口的所有扩展方法,而IList<T>在另一文件中具有相同的方法。另一种方法是将相同的方法(其所有重载)放在相同的部分中,并为该this参数提供所有可能的类,例如让所有Reverse一个文件中的实现。它取决于哪一个可以更好地证明代码量或您或您的组织可能遵循的一些内部约定方面的合理性。

  • 我不使用它,但是我看到一些C / C ++人士喜欢我将在这里描述的方法:仅使用局部方法为类创建局部。这类似于C / C ++的方法,用于定义接口并将方法声明与实现分开。

  • 纯粹出于逻辑上的关注而分开。如果碰巧使用一个大型类,而大型类本身包含多个逻辑操作集,则可以将每个与逻辑相关的代码分成一个单独的部分。通常,此类的存在与关注点分离原则背道而驰,但通常会在现实生活中观察到这种情况,尤其是对于较旧的代码库。相同用户史蒂夫·埃弗斯(Steve Evers)在回答此问题时提到了它们,并以“ 上帝对象”的名字来称呼它们。我个人会使用部分类的方法在对如此大的文件进行任何重构之前对代码进行拆分,以简化我的工作并使重构更加透明。这也将减少涉及SVN等版本控制系统时可能引起的冲突。


14

我从未见过任何人提及它:我曾经partial将嵌套类放在自己的文件中。

我所有的代码文件仅包含一个类,结构,接口或枚举。当文件名显示您要查找的对象的名称时,使查找对象的定义变得容易得多。并且由于Visual Studio尝试将项目文件夹与名称空间进行匹配,因此文件名应与类匹配。

这也意味着NestedClass嵌套在其中的类MyClass将在我的项目中拥有自己的文件:MyClass.NestedClass.cs

partial class MyClass
{
    private class NestedClass
    {
        // ...
    }
}

1
我不知道为什么有人会否决这个答案。提到的做法既不是反模式,也不会引起我所知道的任何问题。
Ivaylo Slavov'4

1
这也解决了保持类文件较小的问题(就代码行而言),同时仍允许正确封装属于内部类的代码。
redcalx16年

10

除了使用生成的代码外,我只见过它们被用来掩盖上帝的对象。试图理解一个新的代码库或浏览同一对象的多个源文件实在令人讨厌。

因此,当您问Why use partial classes?我答案时:除非您使用的是生成的代码,否则不要这样做。


+1。这是我第一次看到这些类型的对象称为名称(神对象),甚至是正式的。学习新知识永远不会太晚。
Ivaylo Slavov

6

代码组织是唯一的原因,但它比起初看起来要深入。如果您有生成零件的局部类,则可以轻松地:

  • 无需在编写的类中检测到手动更改即可重新生成代码(这样就不会覆盖这些部分)。
  • 从测试覆盖率,源代码控制,指标等中排除生成的部分类。
  • 使用生成的代码,而不必强迫您基于继承策略(您仍然可以从其他类继承)。

1

还有一些地方将生成的/隐含的类声明为局部的,因此,如果开发人员需要扩展它们,则它们具有完全的访问权限,而不必担心在整个地方继承和覆盖。如果要尝试捕获一些示例,请在IIS下首次运行Webforms站点后,查看asp.net临时区域中生成的类。


1

我可以想到它们的肮脏用途。

假设您有一些需要通用功能的类,但是您不想将该功能注入到它们之上的继承链中。或者,您有一组使用通用帮助程序类的类。

基本上,您想进行多重继承,但是C#不太可能。因此,您要做的是使用partial创建本质上在C / C ++中的#include。

将所有功能放在一个类中,或使用帮助程序类。然后将帮助程序复制X次,并将其重命名为A,B,C部分类。并将部分内容放在您的A,B,C类上。

免责声明:是的,这是邪恶的。永远不要这样做-特别是如果它会使其他人对您发怒。


Mixins。可以与T4结合使用以避免手动复制...
Peter Taylor

如前所述,这非常类似于mixin。但是,您正在采用一种称为“特征”的概念,它们可以安全地处理您要实现的目标。我在publius-ovidius.livejournal.com/314737.html上有与语言无关的描述, 我一直在寻找C#的干净实现,但还没有看到。
Ovid 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.