.NET中每个文件规则一个类?[关闭]


185

我遵循此规则,但我的一些同事不同意该规则,并争辩说,如果一个班级较小,则可以将其与其他班级放在同一文件中。

我一直听到的另一个论点是:“即使Microsoft也不这样做,那为什么还要这么做?”

对此有什么普遍共识?在某些情况下应避免这种情况?



Answers:


176

每个文件一个类也可以使您更好地了解每次签入的变化,而无需查看文件的差异。


4
同一文件中的更多类只能在一个操作中增强相关类之间的区别。

3
适当的差异查看器可让您查看一次提交的所有差异。
Dykam 2010年

44
我不完全确定这个特定答案如何回答原始帖子的问题。当然,这为将1个班级保留到一个文件中提供了一个理由(尽管Luca和Dykam是有好处的),但是它并不能反映普遍的共识,也没有提供应避免的案例。
罗伯特·戴维斯

3
最佳实践不存在,如果您相信最佳实践可以理解为它们仅适用于给定的上下文。正如其他回应所指出的那样,有时该规则实际上会创建难以维护的代码。随着工具的改进,该规则实际上变得不那么重要了,因为它在项目中更容易找到类和类型。
2011年

262

我讨厌人们绝对考虑时说,您绝对不应该这样或那样主观和挑剔地这样做,就像我们所有人都需要遵循某人对是非的愚蠢观念一样。底线:如果有意义的话,每个文件有多个类是完全可以的。我的意思是说:

  1. 使代码更易于消化和维护
  2. 使解决方案不那么烦人(滚动浏览无数不必要的文件)并且不那么慢
  3. 开发团队可以将其作为本地编码实践

一个很好的例子说明为什么我可能希望每个文件包含多个类:

假设我有几十个自定义异常类,每个异常类都是4个班轮,我可以为每个异常类创建一个单独的文件,也可以对异常进行分组,然后按组分组。对我来说,最合理/最实用的方法是将它们分组,并且只包含几个文件,因为这是更有效的时间/编码方式(我不必右键单击->添加类,重命名50次) ,它使解决方案更整洁,性能更好。


92
+1,000。了解最佳实践的原理并在违反最佳实践之前三思而后行是很棒的。坚持奴隶制是邪恶的。
dsimcha 2010年

19
几十个自定义异常类?这不是问题的真正根源吗?我不仅仅是在这里有些挑剔:我认为大多数时候人们都想将类组合到一个文件中,这是因为他们不必要地创建了太多类型。(话虽如此,也许在实际情况下,几十个定制异常类才有意义)。通常,许多小的无操作类通常是更大问题的征兆。
杰夫·斯坦恩

16
我大部分时间都同意。但是例外是特例。因为正确构建的系统需要适当的异常处理才能处理所有产生合法错误的情况,所以我阅读的大多数最佳实践文章都强调需要创建特定的异常(有时您需要大量异常来处理)。涵盖大型项目的所有业务规则),这样您就不会最终捕获system.exception,这根本不是适当的异常处理。
詹姆斯

6
我同意您不应无缘无故地遵循某些准则,但是我不同意文件中应包含多个类的事实。对我来说,该文件应以该类命名,并且不能包含多个文件。某些语言(java是一种语言)记下了实际上是强制该类在文件名中与该类名匹配的文件中。对我来说,它使新手更容易导航,因此,我相信每个文件一个类都是正确的做法
krystan荣幸

3
就像命名变量一样,每个文件保持一个类并保持文件名和类名同步。Visual Studio对这种方法进行了很好的调整。对于源代码控制系统和在项目中间添加的开发人员而言,这更容易。他们将直观地搜索与类名匹配的文件名。
奥伊贝克2013年

75
static bool GeneralRuleShouldBeFollowed(IGeneralRule rule, IUseCase useCase)
{
    return (rule.Overhead(useCase) 
            < My.PersonalThresholds.ConformismVsPracticality);
}

4
.NET中是否有类似的规则?我也将返回语句结果。:O
Joan Venge

50

如果它们紧密耦合并且至少其中一个很小,我有时会将一个以上的类分组到一个文件中。

一般的“最佳实践”是每个班级只有一个文件。


7
如果您认识到它们是耦合的,为什么不将它们解耦呢?
马特2010年

39
@马特:这被称为避免过度设计。如果您有几个紧密耦合的类,并且将它们解耦会比它提供的实际灵活性增加很多复杂性,那又有什么意义呢?
dsimcha 2010年

9
有时候我喜欢基本上只由该类使用的“数据”类,所以我通常将数据类与用户放在同一文件中,因为数据class通常本身几乎没有逻辑,或者看起来像一个浪费为它创建一个新文件。
Earlz 2010年

3
@马特:有时候我会说辅助类是可以接受的。它们降低了另一门课程的一部分的复杂性,但仍促进了该课程的特定目的。
Jordan Parmer 2010年

6
@TheMatt:解耦:msdn.microsoft.com/en-us/library/… 模块之间的耦合不好,但是在逻辑功能内类之间的协作是不可避免的。
Ben Voigt

25

除了假设性的争论,而是将重点放在带有Visual Studio IDE的Windows .NET和不断发展的软件项目上,在这种情况下,每个文件只有一个类是有意义的。


通常,对于视觉参考而言,每个文件都胜过一类。真。

我不知道Microsoft是否做同样的事情,但是他们确实创建了将一个类拆分为多个文件partial关键字(甚至更严重)。它通常用于将自动生成的设计器代码与同一类自定义代码分开(但有时用于允许不同的开发人员通过不同的文件同时处理该类)。因此,Microsoft确实看到了多个文件的好处,并且使用.NET时,每个人都牢记多个文件组织的想法。

对于嵌套类,您别无选择,只能使用一个文件,或者至少使用其中的类的第一部分。在这种情况下,一个文件是必需的并且可以:

class BicycleWheel {
    class WheelSpoke {
    }
}

否则,为什么要在一个文件中保留多个类?“因为它们很小”彼此关联 的说法没有多大用处,因为最终您的班级将与其他班级关联。最终,您无法根据对象的用途轻松推断文件的文件组织,尤其是随着软件的不断发展。

另外,如果您使用文件夹作为名称空间,则永远不会出现类文件名冲突的情况。当不在像Visual Studio这样的开发环境中时,在文件系统上按文件名查找类也很方便(例如,如果您要使用Notepad或quick / light之类快速编辑类)。

这么多的好理由...


谢谢,“至少它们的第一部分”是什么意思?您的意思是您还可以分离嵌套类?
Joan Venge

1
这是partial我提到的关键字的间接引用。
约翰·K

1
为了记录嵌套类,请访问partial msdn.microsoft.com/zh-cn/library/wa80x488(VS.80).aspx 。出于好奇,我对此进行了查找。
约翰·K

这仅表明默认视图应为逻辑(名称空间/类)而不是物理(文件)。
戴维·施密特

@DavidSchmitt是Visual Studio中的类视图的目的。
扎克2015年

14

在大多数情况下,我遵循每个文件一个类的规则。我经常犯的唯一例外是与特定类紧密相关的枚举的定义。在这种情况下,我会经常在该类的文件中包含枚举的定义。


12

我也相信单个文件中应该包含一种类型。

必须提到此规则的一个例外:具有两个仅在通用参数方面不同的类,例如:

RelayCommand     

RelayCommand<T>

您知道在这种情况下使StyleCop满意的解决方法吗?
乔治·波列沃

不同意的是,泛型类还有另一个约定,即Foo 1.cs for Foo <T>和Foo 2.cs for Foo <T,T1>。
奥伊贝克2013年

@Oybek:如果我有Foo <T>,Foo <U>和Foo <U,T>,该怎么办?怎么办?
AndreiRînea13年

@AndreiRinea它是不可能有Foo<T>Foo<U>同一个命名空间内。但是,如果命名空间不同,则它们通常位于不同的文件夹中。因此,对于Foo<T>Foo<U>它应该是富1.cs and for 富<U,T>`Foo`2.cs。但是每个文件仍然一个类。
奥伊贝克(Oybek),2013年

谢谢你的信息!:)
AndreiRînea13年

7

确实,这归结为个人喜好。每个人都会说“每个文件一个类”,但是我们都有理由在某些情况下避免这种情况。我曾经有一个大型项目,其中包含约300个不同的枚举。当某些枚举仅是三态时,我将不会有300个单独的文件,每个类一个。

同样对于无法找到某些类的人(如果不是全部都以它们的名字命名),是否有理由不使用Find在整个解决方案中查找?使用查找为我节省了在解决方案资源管理器中滚动的宝贵时间。


回复:查找-当我在寻找类型的定义时,我不想看到它的使用位置。此外,查找所花的时间比滚动浏览我可能已经按名称空间划分的文件的按字母顺序排序的列表要长得多。
杰夫·斯坦恩

1
我注意到您已经表明您正在使用按名称空间划分的内容。不幸的是,我们并不是很幸运能够始终与我们能够管理的项目一起工作。
杰森M

6

无论内容多么轻巧,我都认为每个文件一个类/接口/等是必不可少的。

如果我正在使用Visual Studio中的大型解决方案,那么我希望能够看到文件,而不必深入研究。即使使用ReSharper之类的导航工具,我也想要1:1映射。

如果发现很多源文件内容很少或没有内容(也许扩展了一个类但没有添加任何内容),那么也许您应该重新考虑您的设计。



5

我通常每个文件只有一个类,但是您通常必须谨慎决定文件是否可以包含相关的类,例如,对异常进行分组,这些异常可以由您自己和其他开发人员重复使用。在这种情况下,用户只需要包含一个文件,而不需要多个文件。

因此,重点是:应谨慎使用!!!


1
真正的智慧,编程中没有规则是一成不变的。
ChaosPandion

4

在较大的解决方案中,我认为每个文件有一个类非常有价值,并且文件与该类的名称相同。它使查找需要使用的代码变得更加容易。


我发现这种争论在ReSharper之类的工具中价值不大。我按CTRL + T,然后开始输入要查找的类型的名称。
标记

3
是的,但是您是否希望您的应用程序结构依赖于第三方工具?
马格努斯2010年

1
@magnus我并不是说这不是不这样做的理由,而是对某人这样做的理由的吸引力较小。
标记

4

C#的StyleCop工具具有标准规则,在一个名称空间中最多只需要一个顶层类(以及该名称空间中的任意数量的接口,委托和枚举)。

在两个或多个类的情况下,第二个和后续类仅由第一个使用,则这些类可以并且应该是内部类,仅对使用方可见。


3
当您说“在一个命名空间中不超过一个顶级类”时,您的意思是在一个namespace块中,对吗?
丹尼尔·普里登

1
提到的规则是SA1403:AC#文档只能包含一个名称空间。SA1402:AC#文档在根级别只能包含一个类,除非所有类都是部分类并且属于同一类型。
史蒂夫·吉勒姆

4

有时每个文件一个类,但是 ...

当多个类紧密相关时,恕我直言,同一个源文件中的多个类比为每个类指定一个简短的源文件更好。源代码更具可读性和紧凑性(并且使用#region可以比以前更加结构化同一源代码)。

想想也是,有时它是必要在不同的文件(使用传播同一类部分),由于具有20000+行源文件是不是很方便,即使与RAM我有可用的(但这是另外一个问题)。


当然,您应该尝试避免使用包含这么多代码行的类。我想说的是甚至超过1000个都太大了。我还意识到,在遗留代码中并非总是能够做到这一点。
彼得

如果您尝试生成源代码(我的情况是根据其规范为OpenGL生成C#绑定,具有成千上万个入口点),则很难为大量数据考虑一个小类……
Luca

3

有时候,我会把一个小班级和一个大班级放在一起,但前提是它们与对象和它的集合类或工厂紧密联系在一起。

但是,这有一个问题。最终,小类增长到了应在其自己文件中的位置,如果将其移至新文件,则无法轻松访问修订历史记录。

即。

  • 在星期一,我对文件y.css中的类x和y进行了更改
  • 在星期二,我将类x分离到其自己的文件x.css中,因为它已经变得很大
  • 在星期三,我的老板想查看我星期一在类x中所做的更改,因此他查看x.css的历史记录,只有x.css在星期二更改之前不显示历史记录。

1
如果“小类”类似于EventArgs的派生类,该类旨在将信息传递给类事件的接收者怎么办?通过将这样的东西移动到另一个文件中,可以使代码更简洁或更易于维护吗?可以说,这样的事情应该是嵌套的公共类,但是那些似乎也被皱眉了。至于修订历史,该类不会在变更日志中出现吗,难道不应该在代码注释中注释它的来源吗?
supercat

我会将其分类为一个very tightly related类,并保留它,前提是它仅占用少量的屏幕空间,并且不会被其他任何类用于同一目的。
gingerbreadboy

3

这真的有问题吗?:)
确实,像枚举一样,很小的类也可以与其他类放在一起。要遵循一个规则:仅将具有共同点的类放在一起。

题外话-在我的一个项目中,我有一个包含150个类的文件。该文件具有10000行代码。但是它是自动生成的,因此完全可以接受:)


1
我有一个包含120个类和750个子类的文件,该类有500万行,它也是自动生成的。
贝鲁兹

3

放置多个的原因之一 相关内容的类放在一个文件中的是,使使用您的API的可怜的混蛋不必花半天的时间输入导入声明样板,而必须维护代码的可怜的混蛋不必花一半的时间。一天滚动浏览进口报关样板。我的经验法则是,如果您几乎总是同时使用它们的一个很大的子集,而不是一次只使用一个,则多个类属于同一文件。


1
您所说的“进口报关样板”是什么意思?“使用声明”?但是这些类不是位于同一个命名空间中吗?
Joan Venge

3
@Joan:我的意思是必须导入15个不同但相关的模块才能完成一些非常简单的事情。也许它不适用于C#。我不太了解C#,但是在其他语言中,这是一个非常烦人的问题。
dsimcha 2010年

谢谢,这就是为什么我感到困惑。
Joan Venge

2

我这样做,但是仅当这些类以子父形式关联并且子类仅由父类使用时才这样做。


谢谢,但是为什么不将它分成另一个文件呢?只是好奇。
Joan Venge

@henchman说的比我雄辩得多,尤其是当子对象很小时。通常情况下,子类仅是带有少许逻辑的属性
CResults 2010年

2

我通常坚持每个文件一堂课。但是对于在项目范围内使用的类似构造的组,我将予以例外。例如:

  • 一个包含以下内容的EventArgs.cs EventArgs类,因为子类通常只有5-10行代码,但是它们通常由几个不同的类使用。或者,我可以将这些EventArgs类与声明事件的类放在同一文件中。
  • 一个Delegates.cs,其中包含在整个项目中使用的Delegates,因为它们通常每个只有1行。同样,替代方法是将它们与暴露/使用它们的类放在同一文件中。
  • 一个Enums.cs,其中包含enum在整个项目中使用的。(如果有一个enum仅由一个类使用,则通常会private在该类中使用它。)

2

每个文件对一个类进行另一次投票,该文件的名称与该类相同。对我来说,它有助于长期的可维护性。我可以轻松浏览存储库,并查看哪些类是解决方案的一部分,而无需打开项目或任何文件。


2

我99%的时间都遵循它。遵循标准是很好的,但是我也相信灵活性在其中占有一席之地。有时候,似乎很愚蠢地浪费时间来分解事物。在那个时候,我克服了自己,只写了我的代码。


2

到目前为止,响应似乎与人们对该规则的异常有关,所以这是我的:在.NET3.5 SP1中使用DataAnnotations包时,我将类及其元数据“伙伴”类放在一起。否则,它们将始终位于单独的文件中。您知道,大部分时间。除非不是。


2

我很少这样做。例如,如果存在与该类紧密相关但又过于琐碎而无法单独分离的枚举或结构。

或者是一个单独的类,其中包含该主类的某些扩展方法。


1

One case could be:当你的班级共同组成一个module / unit服务于一些主要班级的时helper classes否则不行

看一下ASP.NET MVC 2.0项目源代码。严格遵守此规则


1

我喜欢创建较小的类并确保该类仅执行应做的事情的想法。如果您有多个有助于解决单个问题的类,那么将它们放到同一文件中不会有任何危害。

我不会遵循MS惯例,因为它们不是最佳实践!


1

我没有看到其他人提到的另一点是,当使用每个文件一个类的规则进行开发时,您可以轻松地看到该特定类在使用什么。

例如:您可能有两个班级,其中一个班级使用Linq,而另一个班级则不使用。

如果这些类在同一个文件中,则不查看代码就无法知道哪个类使用了什么。如果每个文件只有一个类,则只需查看文件顶部以查看该类中正在使用的内容即可。如果您要迁移到新的库等,则有帮助。


0

到目前为止,尚未在答案中提及每个文件一个类的另一个原因是,每个文件一个类可以更轻松地在代码审查期间理解PR的影响。它还减少了合并冲突。

当某人发布PR以获得反馈时,我可以查看更改的文件列表,并立即看到与我正在处理的文件有任何重叠之处。根据重叠的部分,我可能想更深入地研究他们的代码,或者给它一个好的命令,因为我很有信心它不会影响我自己的更改。

当两个人在一个多类文件中工作并且都添加了依赖性时,您很有可能using在顶部的块中遇到合并冲突。将类分为文件可将依赖项分开,这样您就可以看到每个类在使用什么,而不会出现这样的冲突。

该规则有一些例外(接口+实现,枚举等),但是比起相反的规则(它通常让初级开发人员将所有无关类的方式捆绑到同一个文件中)相对更好。

每个文件一类是一个明确的规则,无需解释。


文件中的相关类受个人喜好和解释的影响(您可以从此处的所有其他答案中看到何时可以使用),因此这是一个很差的规则。


-1

来回交互非常有趣,并且似乎没有定论,尽管我的总体印象是,在类和文件之间以1-1映射是多数意见,尽管有些人与人之间有例外。

我很好奇您的答案是否取决于您是否是:(1)开发Windows Forms应用程序,Web应用程序,库或其他工具;或(2)是否使用Visual Studio。在使用VS时,似乎每个文件一个类的规则也暗示每个VS项目一个类,因为其他线程的共识似乎是VS解决方案/项目应该镜像到目录/文件的命名和结构中。确实,我的印象是,共识是使项目名称=程序集名称=(嵌套)名称空间名称,然后将所有这些名称映射到目录/文件的命名和结构中。如果这些是正确的准则(或规则),那么所有这些看似正交的组织机制仍将保持同步。


-1

是的,为了便于阅读,每个班级应该有一个文件!刚刚跳入一个项目。我在一个文件中看到许多类。这会让新手很难理解。我们不应该考虑可维护性吗?我们何时开发软件?很多时候,其他开发人员将继续进行开发。我们有命名空间来安排我们的东西,我们不需要文件来做到这一点!


-5

每个文件一个代码项,是的。

其他所有内容都是不当行为-坦率地说,这是RAD受害的迹象。

一旦人们开始适当的软件开发(IoC,设计模式,DDD,TDD等),然后离开“ omg让我们完成这项工作,我不知道如何做,但是我得到了报酬”,人们就会看到这个规则确实非常重要。

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.