While there might not be one right way to format your C# code, agreeing on a consistent style across your team can result in a cleaner, more readable and scalable codebase. A well-organized style guide can help you rein in discrepancies to produce a cohesive final product. This page provides tips and key considerations to keep in mind for naming conventions and code formatting when creating your own style guide.
Note: The recommendations shared here are based on those provided by Microsoft. The best code style guide rules are the ones that work best for your team’s needs.
You can find a code style guide example here or download the full e-book, Create a C# style guide: Write cleaner code that scales.
You can’t define variables with spaces in the name because C# uses the space character to separate identifiers. Casing schemes can alleviate the issue of having to use compound names or phrases in source code.
Listed below are several well-known naming and casing conventions:
Camel case
Also known as camel caps, camel case is the practice of writing phrases without spaces or punctuation, separating words with a single capitalized letter. The very first letter is in lowercase.
Typically, local variables and method parameters appear in camel case. For example:
examplePlayerController
maxHealthPoints
endOfFile
Pascal case
Pascal case is a variation of camel case, where the initial letter is capitalized. Use this for class and method names in Unity development. Public fields can be pascal case as well. For example:
ExamplePlayerController
MaxHealthPoints
EndOfFile
Snake case
In this case, spaces between words are replaced with an underscore character. For example:
example_player_controller
max_health_points
end_of_file
Kebab case
Here, spaces between words are replaced with dashes. The words then appear on a sort of “skewer” of dash characters. For example:
example-player-controller
Max-health-points
end-of-file
The problem with kebab case is that many programming languages use the dash as a minus sign. Additionally, some languages interpret numbers separated by dashes as calendar dates.
Hungarian notation
The variable or function name often indicates its intention or type. For example:
int iCounter
string strPlayerName
Hungarian notation is an older convention and is not commonly used in Unity development.
Consider these rules for your variables and fields:
- Use nouns for variable names: Variable names should be clear and descriptive because they represent a specific thing or state. Use a noun when naming them except when the variable is of the type bool (see below).
- Prefix Booleans with a verb: These variables indicate a true or false value. Often they are the answer to a question, such as: Is the player running? Is the game over?
- Prefix them with a verb to make their meaning more apparent. Often this is paired with a description or condition, e.g., isDead, isWalking, hasDamageMultiplier, etc.
- Use meaningful names. Don’t abbreviate (unless it’s math): Your variable names will reveal their intent. Choose names that are easy to pronounce and search for.
- While single-letter variables are fine for loops and math expressions, don’t abbreviate in other situations. Clarity is more important than any time saved from omitting a few vowels.
- For quick prototyping, you can use short “junk” names temporarily, and then refactor to more meaningful names later on.
- Use pascal case for public fields, and use camel case for private variables: For an alternative to public fields, use properties with a public “getter” (see previous and following sections).
- Avoid too many prefixes or special encoding: You can prefix private member variables with an underscore (_) to differentiate them from local variables.
- Alternatively, use the this keyword to distinguish between member and local variables in context and skip the prefix. Public fields and properties generally don’t have prefixes.
- Some style guides use prefixes for private member variables (m_), constants (k_), or static variables (s_), so the name can reveal more about the variable at a glance.
- Many developers eschew these and rely on the Editor instead. However, not all IDEs support highlighting and color coding, and some tools can’t show rich context at all. Consider this when deciding how (or if) you will apply prefixes together as a team.
- Specify (or omit) access level modifiers consistently: If you leave off the access modifier, the compiler will assume the access level should be private. This works well, but be consistent in how you omit the default access modifier.
- Remember that you’ll need to use protected if you want this in a subclass later.
Enums are special value types defined by a set of named constants. By default, the constants are integers, counting up from zero.
Use pascal case for enum names and values. You can place public enums outside of a class to make them global. Use a singular noun for the enum name.
Note: Bitwise enums marked with the System.FlagsAttribute are the exception to this rule. You typically pluralize these as they represent more than one type.
Follow these standard rules when naming your classes and interfaces:
Use pascal case nouns for class names: This will keep your classes organized.
If you have a MonoBehaviour in a file, the source file name must match: You might have other internal classes in the file, but only one MonoBehaviour should exist per file.
Prefix interface names with a capital “I”: Follow this with an adjective that describes the functionality.
In C#, every executed instruction is performed in the context of a method.
Methods perform actions, so apply these rules to name them accordingly:
Start the name with a verb: Add context if necessary (e.g., GetDirection, FindTarget, etc.)
Use camel case for parameters: Format parameters passed into the method like local variables.
Methods returning bool should ask questions: Much like Boolean variables themselves, prefix methods with a verb if they return a true-false condition. This phrases them in the form of a question (e.g., IsGameOver, HasStartedTurn).
Note: The terms “function” and “method” are often used interchangeably in Unity development. However, because you can’t write a function without incorporating it into a class in C#, “method” is the correct term.
Events in C# implement the observer pattern. This software design pattern defines a relationship in which one object, the subject (or publisher), can notify a list of dependent objects called observers (or subscribers). Thus, the subject can broadcast state changes to its observers without tightly coupling the objects involved.
Several naming schemes exist for events and their related methods in the subject and observers. Try the practices in the following sections.
Name the event with a verb phrase. Be sure to choose one that communicates the state change accurately.
Use the present or past participle to indicate the state of events as before or after. For example, specify “OpeningDoor” for an event before opening a door and “DoorOpened” for an event afterward.
Use the System.Action delegate for events. In most cases, the Action<T> delegate can handle the events needed for gameplay.
You can pass up to 16 input parameters of different types with a return type of void. Using the predefined delegate saves code.
Note: You can also use the EventHandler or EventHandler<TEventArgs> delegates. Agree as a team on how everyone should implement events.
Prefix the event raising method (in the subject) with “On.” The subject that invokes the event typically does so from a method prefixed with “On” (e.g., “OnOpeningDoor” or “OnDoorOpened”).
Prefix the event handling method (in the observer) with the subject’s name and an underscore (_). If the subject is named “GameEvents,” your observers can have a method called “GameEvents_OpeningDoor” or “GameEvents_DoorOpened.”
Decide on a consistent naming scheme for your team and implement those rules in your style guide.
Note: This “event handling method” is not to be confused with the EventHandler delegate.
Create custom EventArgs only if necessary. If you need to pass custom data to your Event, create a new type of EventArgs, either inherited from System.EventArgs or from a custom struct.
Use namespaces to ensure that your classes, interfaces, enums, etc. don’t conflict with those already existing from other namespaces, or the Global Namespace. Namespaces can also prevent conflicts with third-party assets from the Unity Asset Store or other test scenes that won’t be part of the final version of the project.
When applying namespaces:
Use pascal case without special symbols or underscores.
Add a using directive at the top of the file to avoid repeated typing of the namespace prefix.
Create sub-namespaces as well. Use the dot(.) operator to delimit the name levels, allowing you to organize your scripts into hierarchical categories. For example, you can create “MyApplication.GameFlow,” “MyApplication.AI,” “MyApplication.UI,” and so on, to hold different logical components of your game.
In code, these classes are referred to as Enemy.Controller1 and Enemy.Controller2, respectively. Add a using line to save typing out the prefix (e.g., using Enemy;).
When the compiler finds the class names Controller1 and Controller2, it understands you mean Enemy.Controller1 and Enemy.Controller2.
If the script needs to refer to classes with the same name from different namespaces, use the prefix to differentiate them. For instance, if you have a Controller1 and Controller2 class in the Player namespace, you can write out Player.Controller1 and Player.Controller2 to avoid any conflicts. Otherwise, the compiler will report an error.
Get more code style tips
Learn more about general formatting here or check out the full e-book. You can also explore our code style guide example.