123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- .. _doc_c_sharp_styleguide:
- Style Guide
- ===========
- Having well-defined and consistent coding conventions is important for every project, and Godot
- is no exception to this rule.
- This page contains a coding style guide which is followed by developers and contributors of Godot
- itself. As such, it is mainly intended for those who want to contribute to the project, but since
- the conventions and guidelines mentioned in this article are those most widely adopted by the users
- of the language, we encourage you to do the same, especially if you do not have such a guide yet.
- .. note:: This article is by no means an exhaustive guide on how to follow the standard coding
- conventions or best practices. If you feel unsure of an aspect which is not covered here,
- please refer to more comprehensive documentation, such as
- `C# Coding Conventions <https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions>`_ or
- `Framework Design Guidelines <https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines>`_.
- Language Specification
- ----------------------
- Currently, Godot uses C# version 6.0 in its engine and example source code. So, before we move to
- a newer version, care must be taken to avoid mixing language features only available in C# 7.0 or
- later, such as pattern matching or expression-bodied members inside get/set accessors.
- For detailed information of C# features in different versions, please see
- `What's New in C# <https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/>`_.
- Formatting Conventions
- ----------------------
- * If you create a new file, make sure that it uses linefeed (*LF*) characters to break lines, not *CRLF* or *CR*.
- * Use UTF-8 encoding without a byte order mark (BOM <https://en.wikipedia.org/wiki/Byte_order_mark>).
- * Use 4 spaces instead of tabs for indentation (which is referred to as 'soft tabs').
- Line Breaks and Blank Lines
- ---------------------------
- For a general indentation rule, follow `The 'Allman Style' <https://en.wikipedia.org/wiki/Indentation_style#Allman_style>`_
- which recommends placing the brace associated with a control statement on the next line, indented to
- the same level:
- .. code-block:: csharp
- // Use this style:
- if (x > 0)
- {
- DoSomething();
- }
- // NOT this:
- if (x > 0) {
- DoSomething();
- }
- However, you may choose to omit line breaks inside brackets,
- * For simple property accessors.
- * For simple object, array, or collection initializers.
- * For abstract auto property, indexer, or event declarations.
- .. code-block:: csharp
- // You may put the brackets in a single line in following cases:
- public interface MyInterface
- {
- int MyProperty { get; set; }
- }
- public class MyClass : ParentClass
- {
- public int Value
- {
- get { return 0; }
- set
- {
- ArrayValue = new [] {value};
- }
- }
- }
- Insert a blank line,
- * After *using* statement list.
- * Between method, properties, and inner type declarations.
- Field and constant declarations can be grouped together according to relevance. In that case, consider
- inserting a blank line between the groups for easier reading.
- Avoid inserting a blank line,
- * After an opening bracket ('{').
- * Before a closing bracket ('}').
- * After a comment block, or a single line comment.
- * Adjacent to another blank line.
- .. code-block:: csharp
- using System;
- using Godot;
- // Blank line after using list.
- public class MyClass
- { // No blank line after '{'.
- public enum MyEnum
- {
- Value,
- AnotherValue // No blank line before '}'.
- }
- // Blank line around inner types.
- public const int SomeConstant = 1;
- public const int AnotherConstant = 2;
- private Vector3 _x;
- private Vector3 _y; // Related constants or fields can be
- // grouped together.
- private float _width;
- private float _height;
- public int MyProperty { get; set; }
- // Blank line around properties.
- public void MyMethod()
- {
- // Some comment.
- AnotherMethod(); // No blank line after a comment.
- }
- // Blank line around methods.
- public void AnotherMethod()
- {
- }
- }
- Consider breaking a line when it's longer than 100 characters. And it's also a good practice to
- insert a line feed (LF) character at the end of a file because some utilities have trouble
- recognizing the last line without it (i.e. Linux's *cat* command).
- Using Spaces
- ------------
- Insert a space,
- * Around a binary and tertiary operator.
- * Between an opening parenthesis and *if*, *for*, *foreach*, *catch*, *while*, *lock* or *using* keywords.
- * Before and within a single line accessor block.
- * Between accessors in a single line accessor block.
- * After a comma.
- * After a semi-colon in a *for* statement.
- * After a colon in a single line *case* statement.
- * Around a colon in a type declaration.
- * Around a lambda arrow.
- * After a single line comment symbol ('//'), and before it if used at the end of a line.
- Do not use a space,
- * After a type cast parentheses.
- * Within single line initializer braces.
- The following example shows a proper use of spaces, according to some of the the above mentioned conventions:
- .. code-block:: csharp
- public class MyClass<A, B> : Parent<A, B>
- {
- public float MyProperty { get; set; }
- public float AnotherProperty
- {
- get { return MyProperty; }
- }
- public void MyMethod()
- {
- int[] values = {1, 2, 3, 4}; // No space within initializer brackets.
- int sum = 0;
- // Single line comment.
- for (int i = 0; i < values.Length; i++)
- {
- switch (i)
- {
- case 3: return;
- default:
- sum += i > 2 ? 0 : 1;
- break;
- }
- }
- i += (int)MyProperty; // No space after a type cast.
- }
- }
- Naming Conventions
- ------------------
- Use *PascalCase* for all namespaces, type names and member level identifiers (i.e. methods, properties,
- constants, events), except for private fields:
- .. code-block:: csharp
- namespace ExampleProject
- {
- public class PlayerCharacter
- {
- public const float DefaultSpeed = 10f;
- public float CurrentSpeed { get; set; }
- protected int HitPoints;
- private void CalculateWeaponDamage()
- {
- }
- }
- }
- Use *camelCase* for all other identifiers (i.e. local variables, method arguments), and use
- underscore('_') as a prefix for private fields (but not for methods or properties, as explained above):
- .. code-block:: csharp
- private Vector3 _aimingAt; // Use '_' prefix for private fields.
- private void Attack(float attackStrength)
- {
- Enemy targetFound = FindTarget(_aimingAt);
- targetFound?.Hit(attackStrength);
- }
- There's an exception with acronyms which consist of two letters like *'UI'* which should be written in
- upper case letters when used where Pascal case would be expected, and in lower case letters otherwise.
- Note that *'id'* is **not** an acronym, so it should be treated as a normal identifier:
- .. code-block:: csharp
- public string Id { get; }
- public UIManager UI
- {
- get { return uiManager; }
- }
- It is generally discouraged to use a type name as a prefix of an identifier like *'string strText'*
- or *'float fPower'*, for example. However, there's an exception about interfaces, in which case they
- **should** be named using an upper case *'I'* as a prefix, like *'IInventoryHolder'* or *'IDamageable'*.
- Lastly, consider choosing descriptive names and do not try to shorten them too much if it affects
- readability.
- For instance, if you want to write a code to find a nearby enemy and hit with an weapon, prefer
- .. code-block:: csharp
- FindNearbyEnemy()?.Damage(weaponDamage);
- Rather than,
- .. code-block:: csharp
- FindNode()?.Change(wpnDmg);
- Implicitly Typed Local Variables
- --------------------------------
- Consider using implicitly typing (*'var'*) for declaration of a local variable, but do so
- **only when the type is evident** from the right side of the assignment:
- .. code-block:: csharp
- // You can use `var` for these cases:
- var direction = new Vector2(1, 0);
- var value = (int)speed;
- var text = "Some value";
- for (var i = 0; i < 10; i++)
- {
- }
- // But not for these:
- var value = GetValue();
- var velocity = direction * 1.5;
- // It's generally a better idea to use explicit typing for numeric values, especially with
- // the existence of 'real_t' alias in Godot, which can either be double or float depending
- // on the build configuration.
- var value = 1.5;
- Other Considerations
- --------------------
- * Use explicit access modifiers.
- * Use properties instead of non-private fields.
- * Use modifiers in this order: *'public/protected/private/internal virtual/override/abstract/new static readonly'*.
- * Avoid using fully qualified names or *'this.'* prefix for members when it's not necessary.
- * Remove unused *'using'* statements and unnecessary parentheses.
- * Consider omitting default initial value for a type.
- * Consider using null-conditional operators or type initializers to make the code more compact.
- * Use safe cast when there is a possibility of the value being a different type, and use direct cast otherwise.
|