One class per file rule in .NET?

C#.Net

C# Problem Overview


I follow this rule but some of my colleagues disagree with it and argue that if a class is smaller it can be left in the same file with other class(es).

Another argument I hear all the time is "Even Microsoft doesn't do this, so why should we?"

What's the general consensus on this? Are there cases where this should be avoided?

C# Solutions


Solution 1 - C#

I hate it when people think in absolutes and say you should never do this or that with something subjective and nit-picky like this, as if we all need to conform to someones stupid idea of right and wrong. Bottom line: having more than one class per file is totally fine if it makes sense. By makes sense I mean things like:

  1. Makes the code easier to digest and maintain
  2. Makes the solution less annoying (scrolling through countless unnecessary files) and less slow
  3. The dev team is okay with it as a local coding practice

A really good example of why I may want multiple classes per file:

Say I've got a few dozen custom exception classes, each one is a 4 liner, I could have a separate file for each one or I could group the exceptions and have a file per group. For me what seems the most rational/pragmatic approach is to group them, and just have a few files, because it's more efficient time/coding wise (I don't have to right-click -> Add Class, rename, 50 times), it keeps the solution less cluttered and better performing.

Solution 2 - C#

One class per file also gives you a better idea of what each check in is changing without looking at the diffs of the file.

Solution 3 - C#

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

Solution 4 - C#

I sometimes group more than one class within a file if they are tightly coupled and at least one of them is very small.

General 'best practice' is to have one file per class.

Solution 5 - C#

Beyond hypothetical arguments and focusing instead on Windows .NET with Visual Studio IDE and growing software projects, it just makes sense in this context to have one class per file.


In general, for visual reference nothing beats one class per file. Really.

I don't know if Microsoft does or doesn't do the same, however they did create the partial keyword to split one class over multiple files (this is even more severe). It's often used to split the auto-generated designer code from your custom code in the same class (but sometimes is used to allow different developers to work on the class at the same time via different files). So Microsoft does see benefits of multiple files and everybody has multiple file organization thoughts in mind for sure with .NET.

For nested classes you have no choice but to use one file, or at least the first parts of the classes in them. One file is necessary and fine in this case:

class BicycleWheel {
    class WheelSpoke {
    }
}

Otherwise why would you keep multiple classes in one file? The argument "because they're small" or associated with each other doesn't hold much water because eventually your classes will be associated with other classes. Ultimately you can't easily infer in-file organization of objects based on their usage especially as software continues to grow.

Additionally if you use folders for namespaces then you'll never have a class filename clash. It's also convenient to locate a class by filename on the file system when not inside a development environment like Visual Studio (e.g. if you want to quickly edit a class with Notepad or something quick/light).

So many good reasons...

Solution 6 - C#

In the vast majority of cases, I follow the one class per file rule. The only exception I regularly make is the definition of an enum that is tightly coupled to a specific class. In that one case, I will frequently include the enum's definition in that class' file.

Solution 7 - C#

I, too, believe there should be one type included in a single file.

There is one exception to this rule that must be mentioned: Having two classes that differ only by a generic argument such as:

RelayCommand     

and

RelayCommand<T>

Solution 8 - C#

Really, this boils down to personal preference. Everybody will say "one class per file", but we all have our reasons for avoiding that in certain circumstances. I used to have a large project that had about 300 different enums. No way am I going to have 300 seperate files, one for each class, when some of the enums only were tri-state.

Also for people that can't find certain classes if they aren't all in files named after what they are, is there a reason you don't use Find looking in the entire solution? Using Find saves me valuable time scrolling through Solution Explorer.

Solution 9 - C#

The StyleCop tool for C# has standard rules that require no more than one top-level class in one namespace (plus any number of interfaces, delegates and enums in that namespace).

In cases of two or more classes where the second and subsequent classes are only ever used by the first, those could and should be inner classes, visible only to the consuming class.

Solution 10 - C#

I find that grouping a class with it's standard factory class in the same file is very useful.

Solution 11 - C#

No matter how lightweight the content, I think one class / interface / etc. per file is essential.

If I'm working on a big solution in Visual Studio I want to be able to see the files and not have to delve inside to see. Even with navigation tools like ReSharper, I want a 1:1 mapping.

If you find a lot of source files with little or no content (maybe extending a class but adding nothing to it) then perhaps you should rethink your design.

Solution 12 - C#

I would normally have one class per file but you would normally have to use your discretion to see if the file could contain related classes e.g. grouping your exceptions which can be re-used by yourself and other developers. In this case, the user only needs one file to be included rather than multiple files.

So the point is: discretion should be used!!!

Solution 13 - C#

In larger solutions I think it is very valuable to have one class per file and that the file is named the same thing as the class. It makes it much easier to locate the code you need to work in.

Solution 14 - C#

Sometime one class per file, but...

When multiple classes are stricly related, more than one class in the same source file is, IMHO, BETTER than dedicating a short source file to each class. The source is more readable and compact (and using #region the same source can be be more structured than before).

Consider also that sometimes it's NECESSARY to spread the same class across different files (using partial), since having a 20000+ line source file is not handy even with the RAM I have available (but this is another question).

Solution 15 - C#

I only do this rarely. For example if there is an enumeration or struct that is closely related to the class yet too trivial to be separated on its own.

Or a separate class to contain some extension methods for that main class.

Solution 16 - C#

Is that really a problem?:)
Really small classes, just like enums, can be put together with others. There's one rule to follow: put together only classes that have something in common.

As a digression - in one of my projects I have a file that has 150 classes inside. The file has 10000 lines of code. But it's auto generated so it's fully acceptable :)

Solution 17 - C#

On occasion I will leave a small class in with a larger class but only if they are very tightly related like an object and it's collection class or factory.

There is one problem with this though. Eventually the small class grows to the point at which it should be in its own file, if you move it to the new file you lose easy access to your revision history.

ie.

  • on monday I make a change to my classes x and y in file y.css
  • on tuesday I seperate class x in to its own file x.css because it has grow to large
  • on wednesday my boss wants to see what I changed in class x on monday so he looks at the history for x.css, only x.css doesn't show the history before tuesdays changes.

Solution 18 - C#

One reason for putting multiple related classes in one file is so that the poor bastard who uses your API doesn't have to spend half a day typing import declaration boilerplate and the poor bastard who has to maintain the code doesn't have to spend half a day scrolling through import declaration boilerplate. My rule of thumb is that multiple classes belong in the same file if you would almost always use a large subset of them at the same time instead of just one at a time.

Solution 19 - C#

I do this, but only when the classes are related in a child-parent fashion and the child classes are ONLY used by the parent.

Solution 20 - C#

One case could be: when your classes jointly form a module / unit that serves some main classes like helper classes, other wise no.

have a look at ASP.NET MVC 2.0 project source code. It strictly follows this rule

Solution 21 - C#

The responses so far seem to revolve around people's exceptions to the rule, so here's mine: I keep classes and their metadata 'buddy' classes together when using the DataAnnotations package in .NET3.5 SP1. Otherwise, they're always in seperate files. You know, most of the time. Except when they aren't.

Solution 22 - C#

I usually stick with one class per file. But I will make exceptions for groups of similar constructs that are used project-wide. For example:

  • An EventArgs.cs that contains any EventArgs subclasses, since they're usually only 5-10 lines of code each, but they typically are used by several different classes. Alternatively, I might put the EventArgs classes in the same file as the class that declares the events.
  • A Delegates.cs that contains Delegates that are used throughout the project, since they're usually only 1 line each. Again, the alternative is to put them in the same file with the class that exposes/consumes them.
  • An Enums.cs that contains enums used throughout the project. (If there's an enum that's used only by one class, I'll usually make it private to that class.)

Solution 23 - C#

Another vote for one class per file with the file being named the same as the class. For me, it helps with long term maintainability. I can easily look through the repository and see what classes are part of a solution without having to open the project or any of the files.

Solution 24 - C#

I follow it 99% of the time. It's good to follow standards, but I also believe flexibility has its place. Sometimes it just seems like a silly waste of time to break things apart. In those times, I get over myself and just write my code.

Solution 25 - C#

I like the idea of creating smaller classes and making sure that the class is doing only what it is supposed to do. If you have multiple classes which are contributing to solve a single problem then there is no harm in putting them together in the same file.

I would not follow MS practices as they are not the BEST PRACTICES!

Solution 26 - C#

Another point I have not seen anyone else mention is that when you develop using the one class per file rule you can easily see what that specific class is using.

For example: you may have two classes where one class uses Linq and the other does not.

If these classes were in the same file you would not be able to tell without looking through the code which class uses what. When it is one class per file all you have to do is look at the top of the file to see exactly what is being used in that class. Helps if you are ever migrating over to a new lib etc.

Solution 27 - C#

Another reason for one-class-per-file that hasn't been mentioned in the answers posted so far is that one-class-per-file makes it easier to understand the impact of a PR during a code review. It also reduces merge conflicts.

When someone posts a PR for feedback I can look at the list of files changed and immediately see any overlap with what I might be working on. Depending on the overlap I might want to look at their code more deeply or give it an OK because I'm fairly confident it isn't going to affect my own changes.

When two people are working in a multi-class file and both add a dependency there's a good chance you'll get a merge conflict in the using block at the top. Separating the classes into files separates the dependencies so you can see what each class is using and you don't get conflicts like this.

There are exceptions to this rule (interface + implementation, enums, ...) but it's a better starting place than the opposite which typically lets junior developers bundle all manner of unrelated classes into the same file.

> One-class-per-file is a clear unambiguous rule not subject to interpretation.


> Related-classes-in-a-file is subject to personal preferences and interpretation (as you can see from all the other answers here as > to when it's OK to use) and thus is a poor rule.

Solution 28 - C#

The back and forth has been very interesting, and seemingly inconclusive, though my general impression is that a 1-1 mapping between classes and files is the majority opinion, though with some person-by-person exceptions.

I'm curious if any of your answers vary depending on whether you are: (1) developing a Windows Forms app, a Web app, a Library, or whatever; or (2) using Visual Studio or not. In using VS, it would appear that the one class per file rule would also imply one class per VS project since the concensus in other threads seems to be that VS solutions/projects should be mirrored in the directory/file naming and structure. Indeed, my impression is that the concensus is to have the project name = assembly name = (nested) namespace name, all of which would then be mirrored in the directory/file naming and structure. If those are the right guidelines (or rules), then all these seemingly orthogonal organizing mechanisms would be nevertheless kept in sync.

Solution 29 - C#

Yes for the sake of readability we should have one file per class!. Just jumped into a project. I see many classes in one file. it just makes it so hard for a new guy to understand it. shouldnt we think of maintainibility? when we develop a software? many times development will continue by other developers. We have namespaces to arrange our stuff, we dont need files to do that!.

Solution 30 - C#

One code item per file, yes.

Everything else is a malpractice - and, quite frankly, a sign of RAD victimness.

As soon as one starts proper software development (IoC, design patterns, DDD, TDD, etc...) and leaves the "omg lets get this done, I have no idea how, but I get paid" playground, one will see that this rule really, really, matters.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoan VengeView Question on Stackoverflow
Solution 1 - C#JamesView Answer on Stackoverflow
Solution 2 - C#MarkView Answer on Stackoverflow
Solution 3 - C#Jeremy BellView Answer on Stackoverflow
Solution 4 - C#Phil RykoffView Answer on Stackoverflow
Solution 5 - C#John KView Answer on Stackoverflow
Solution 6 - C#Greg DView Answer on Stackoverflow
Solution 7 - C#Andrei RîneaView Answer on Stackoverflow
Solution 8 - C#Jason MView Answer on Stackoverflow
Solution 9 - C#Steve GilhamView Answer on Stackoverflow
Solution 10 - C#Robert DavisView Answer on Stackoverflow
Solution 11 - C#MikeView Answer on Stackoverflow
Solution 12 - C#akapetView Answer on Stackoverflow
Solution 13 - C#Chris ClarkView Answer on Stackoverflow
Solution 14 - C#LucaView Answer on Stackoverflow
Solution 15 - C#puffpioView Answer on Stackoverflow
Solution 16 - C#IamDeveloperView Answer on Stackoverflow
Solution 17 - C#gingerbreadboyView Answer on Stackoverflow
Solution 18 - C#dsimchaView Answer on Stackoverflow
Solution 19 - C#CResultsView Answer on Stackoverflow
Solution 20 - C#AsadView Answer on Stackoverflow
Solution 21 - C#Brant BobbyView Answer on Stackoverflow
Solution 22 - C#Daniel PrydenView Answer on Stackoverflow
Solution 23 - C#Tim ScarboroughView Answer on Stackoverflow
Solution 24 - C#Mike PaterasView Answer on Stackoverflow
Solution 25 - C#azamsharpView Answer on Stackoverflow
Solution 26 - C#Kieran OldhamView Answer on Stackoverflow
Solution 27 - C#Ian MercerView Answer on Stackoverflow
Solution 28 - C#Steve RehlingView Answer on Stackoverflow
Solution 29 - C#CetiView Answer on Stackoverflow
Solution 30 - C#Turing CompleteView Answer on Stackoverflow