Соглашения об именовании
Naming conventions
There’s a deep psychology involved in giving something a name. A name tells us how that entity fits into the world. What is it? Who is it? What can it do for us? The names of your variables, classes, and methods aren’t mere labels. They carry weight and meaning. Good naming style impacts how someone reading your program can comprehend the idea you’re trying to convey. Here are some guidelines to consider for naming.
Identifier names An identifier is any name you assign to a type (class, interface, struct, delegate, or enum), member, variable, or namespace. Avoid special characters (backslashes, symbols, Unicode characters) in your identifiers, even though C# permits them. These can interfere with certain Unity command-line tools. Steer clear of unusual characters to ensure compatibility with most platforms.
Casing terminology You can’t define variables with spaces in the name because C# uses the space character to separate identifiers. Casing schemes can alleviate the problem of using compound names or phrases in source code. There are several well-known naming and casing conventions.
Camel case (camelCase) 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 lowercase. Local variables and method parameters are camel case. For example: examplePlayerController maxHealthPoints endOfFile
Pascal case (PascalCase) Pascal case is a variation of camel case, where the initial letter is capitalized. Use this for class, public fields and method names in Unity development. For example: ExamplePlayerController MaxHealthPoints EndOfFile
Snake case (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 (kebab-case) Here, spaces between words are replaced with dashes. The words appear on a “skewer” of dash characters. For example: example-player-controller Max-health-points end-of-file naming-conventions-methodology The Kebab-case is widely used in web technologies and namely for CSS. We are also recommending it for use with UI Toolkit USS as we will be covering later in the guide.
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 common in Unity development.
Fields and variables Consider these rules for your variables and fields: —
Use nouns for variable names: Variable names should be descriptive, clear, and unambiguous because they represent a thing or state. So 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 should reveal their intent. Choose names that are easy to pronounce and search for – not just for your colleagues but also to provide extra context to the code for when using AI tools, as this can contribute to more accurate code generation and suggestions. Choose identifier names that are easily readable. For example, a property named HorizontalAlignment is more readable than AlignmentHorizontal. Single letter variables are fine for loops and math expressions, but otherwise, don’t abbreviate. Clarity is more important than any time saved from omitting a few vowels. You might be tempted to use short “junk” names when prototyping, but this won’t save you time if you need to refactor the code at a later date. Pick meaningful names from the beginning.
Examples to avoid
Use instead
Notes
int dint elapsedTimeInDaysAvoid single letter abbreviations unless a counter or expression. Be specific about the measurement unit.
int hp,int healthPoints, string teamName,Variable names reveal intent. Make names searchable and pronounceable.
string tName, int mvmtSpeed
int movementSpeedint getMovementSpeedint movementSpeedUse nouns. Reserve verbs for methods unless it’s a bool (below).
bool deadbool isDead,Booleans ask a question that can be answered true or false.
bool isPlayerDead —Use pascal case (MyPropertyName) for public fields. Use camel case (myPrivateVariable) for private variables: For an alternative to public fields, use Properties with a public getter (see Formatting below).
Consider using prefixes or special encoding: Some guides suggest adding a prefix to private member variables with an underscore (_) to differentiate them from local variables. In our style guides we 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. For example, movementSpeed becomes m_movementSpeed. Mixing PascalCase with the prefix such as m_MovementSpeed is also an option but is generally less commonly used in modern C#. 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. Local variables and parameters use camel case with no prefix. Many developers eschew these and rely on the editor instead. IDEs today support highlighting, color coding, and rich context.
Fields are automatically initialized to their default values: Default value is typically 0 for numeric types like int, while reference type fields (e.g., objects) are initialized to null by default, and bool fields are initialized to false by default. Given this, explicitly setting a field to its default value is generally unnecessary.
Name constant variables with k_ as prefix and in PascalCase: This helps to distinguish constants from regular variables or properties, and makes the code easier to read and maintain.
// EXAMPLE: constants
public class MathConstants { public const int k_MaxItems = 100; }
Specify (or omit) access level modifiers consistently: If you leave off the access modifier, the compiler will assume the access level to be private. This works well, but be consistent in how you omit the default access modifier.MSFT guidelines recommended to explicitly specify private to make the access level clear and to avoid any ambiguity. Other guides argue you should drop redundant access specifiers (leave off ‘private’ at type scope) and, similarly, drop redundant initializers (i.e. no ‘= 0’ on the ints, ‘= null’ on ref types, etc.). Remember that you’ll need to use protected if you want this in a subclass later. We recommend to leave out things that are implicit and thus redundant (such as private) for simplicity if you agree that it doesn’t negatively affect readability for you. Favor readability over brevity: As this example from the MSFT documentation shows, the property name CanScrollHorizontally is better than ScrollableX (an obscure reference to the X-axis).
Example code snippets The code snippets in this guide are non-functional and abbreviated. They’re presented here to show style and formatting. You can also reference this example C# style sheet for Unity developers, which is a modified version of Microsoft’s Framework Design Guidelines. This represents just one example of how you can set up your team’s style guide. Review each rule in the example style guide and customize it to your team’s preferences. The specifics of an individual rule are less important than having everyone agree to follow it consistently. When in doubt, rely on your team’s own guide to settle any style disagreements.
// EXAMPLE:
public and private variables are grouped together. public float DamageMultiplier = 1.5f;
public float MaxHealth;
public bool IsInvincible;
private bool m_isDead;private float m_currentHealth;
public void InflictDamage(float damage, bool isSpecialDamage) {
// local variable int totalDamage = damage;
// local variable versus
public member variable if (isSpecialDamage) { totalDamage *= DamageMultiplier; }
// local variable versus
private member variable if (totalDamage > _currentHealth) { /// ... }
}
—Use one variable declaration per line: It’s less compact, but enhances readability.
Avoid redundant names: If your class is called Player, you don’t need to create member variables called PlayerScore or PlayerTarget. Trim them down to Score or Target.
Drop redundant initializers (i.e. no ‘= 0’ on the ints, ‘= null’ on ref types, etc.).
Avoid jokes or puns: While they might elicit a chuckle now, the infiniteMonkeys or dudeWheresMyChar variables won’t hold up after a few dozen reads, and more importantly, it violates our previous stated goal of naming revealing context.
While avoiding ambiguity and always looking for ways to improve readability, you can use var when the type is clear from the context: With good naming ambiguity should be less of an issue because variable names already convey the intent. Refactoring is simpler with var since it abstracts away the specific type, reducing the number of places where code needs to be updated when types change. In foreach loops, var ensures that the iteration variable matches the type provided by the enumerator. If you explicitly declare a mismatched type, the compiler may allow it, leading to runtime errors.
// EXAMPLE: good use of
var var powerUps = new List<PowerUps>();
var dictionary = new Dictionary<string, List<GameObject>>();
// AVOID: potential ambiguity
var powerUps = PowerUpManager.GetPowerUps();Enums Enums are special value types defined by a set of named constants. By default, the constants are integers, counting up from 0. 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 as it represents a single value from a set of possible values. They should have no prefix or suffix. Note: bitwise enums marked with the System.FlagsAttribute attribute are the exception to this rule. You typically pluralize these as they represent more than one type. // EXAMPLE: enums use singular nouns
public enum WeaponType { Knife, Gun, RocketLauncher, BFG }
public enum FireMode {
None = 0, Single = 5, Burst = 7, Auto = 8,
}
// EXAMPLE: but a bitwise enum is plural (you can also use the 1 << bitnum style)
[Flags] public enum AttackModes {
// Decimal// BinaryNone = 0,
// 000000Melee = 1,
// 000001Ranged = 2,
// 000010Special = 4,
// 000100MeleeAndSpecial = Melee | Special
// 000101Classes and interfaces Follow these standard rules when naming your classes and interfaces: —
Use Pascal case nouns or noun phrases for class names: This distinguishes type names from methods, which are named with verb phrases.
If you have a Monobehaviour in a file, the source file name must match: You may 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.
// EXAMPLE: Class formatting
public class ExampleClass : MonoBehaviour {
public int PublicField;
public static int MyStaticField;
private int m_packagePrivate;
private int m_myPrivate;
private static int m_myPrivate;
protected int m_myProtected;
public void DoSomething() { }
}
// EXAMPLE: Interfaces
public interface IKillable { void Kill(); }
public interface IDamageable<T> { void Damage(T damageTaken); }Methods In C#, every executed instruction is performed in the context of a method. Note: “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 accepted term. Methods perform actions, so apply these rules to name them accordingly: —
Start the name with a verb or verb phrases: 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.
// EXAMPLE: Methods start with a verb
public void SetInitialPosition(float x, float y, float z) {
transform.position = new Vector3(x, y, z);
}
// EXAMPLE: Methods ask a question when they return bool
public bool IsNewPosition(Vector3 currentPosition) {
return (transform.position == newPosition);
}Events and event handlers 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. You can learn more about using the observer and other design patterns in your Unity projects in the e-book Level up your code with design patterns and SOLID. Several naming schemes exist for events and their related methods in the subject and observers. Try these practices: —
Name the event with a verb phrase: Choose a name that communicates the state change accurately. Use the present or past participle to indicate events “before” or “after.” For example, specify “OpeningDoor” for an event before opening a door or “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 may pass anywhere from 0 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 will implement events. // EXAMPLE: Events // using System.Action delegate public event Action OpeningDoor;
// event before
public event Action DoorOpened;// event afterpublic event Action<int> PointsScored;
public event Action<CustomEventArgs> ThingHappened;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.”
// raises the Event if you have subscribers
public void OnDoorOpened() { DoorOpened?.Invoke(); }
public void OnPointsScored(int points) { PointsScored?.Invoke(points); }Consider prefixing the event handling method (in the observer) with the subject’s name and underscore (_): If the subject is named “GameEvents,” your observers can have a method called “GameEvents_OpeningDoor” or “GameEvents_DoorOpened.” Note that this is called the “event handling method”, not to be confused with the EventHandler delegate.
Create custom EventArgs only as 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.
// define an EventArgs if needed // EXAMPLE: read-only, custom struct used to pass an ID and Color
public struct CustomEventArgs {
public int ObjectID { get; }
public Color Color { get; }
public CustomEventArgs(int objectId, Color color) {
this.ObjectID = objectId;
this.Color = color;
}
}Namespaces Use namespaces to ensure that your classes, interfaces, enums, etc. won’t conflict with existing ones from other namespaces or the global namespace. Namespaces can also prevent conflicts with third-party assets from the Asset Store. When applying namespaces: —
Use PascalCase 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.
Some prefer to have namespaces that reflect the folder structure of the project as having logically grouped related classes and components together, also makes it easier to find and understand the structure of the codebase.
namespace Enemy {
public class Controller1 : MonoBehaviour { ... }
public class Controller2 : MonoBehaviour { ... }
}
In code, these classes are referred to as Enemy.Controller1 and Enemy.Controller2, respectively. Add a using line to save typing out the prefix: 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 PlayerController2 to avoid any conflicts. Otherwise, the compiler will report an error.