123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- .. _doc_c_sharp_styleguide:
- C# 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 of and contributors to 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
- ----------------------
- Godot currently uses **C# version 7.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.1 or
- later.
- For detailed information on C# features in different versions, please see
- `What's New in C# <https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/>`_.
- Formatting
- ----------
- General guidelines
- ~~~~~~~~~~~~~~~~~~
- * Use line feed (**LF**) characters to break lines, not CRLF or CR.
- * Use one line feed character at the end of each file, except for `csproj` files.
- * Use **UTF-8** encoding without a `byte order mark <https://en.wikipedia.org/wiki/Byte_order_mark>`_.
- * Use **4 spaces** instead of tabs for indentation (which is referred to as "soft tabs").
- * Consider breaking a line into several if it's longer than 100 characters.
- 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 a list of ``using`` statements.
- * Between method, properties, and inner type declarations.
- * At the end of each file.
- 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 ``{``, the opening brace.
- * Before ``}``, the closing brace.
- * 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; // Related constants or fields can be
- private Vector3 _y; // 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()
- {
- }
- }
- Using spaces
- ~~~~~~~~~~~~
- Insert a space:
- * Around a binary and ternary 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 which is not at the end of a line.
- * After a semicolon 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 type cast parentheses.
- * Within single line initializer braces.
- The following example shows a proper use of spaces, according to some of 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
- an underscore (``_``) as a prefix for private fields (but not for methods or properties, as explained above):
- .. code-block:: csharp
- private Vector3 _aimingAt; // Use a `_` 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
- uppercase letters where PascalCase would be expected, and in lowercase 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. An exception is made, however, for interfaces, which
- **should**, in fact, have an uppercase letter ``I`` prefixed to their names, 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 code to find a nearby enemy and hit it with a weapon, prefer:
- .. code-block:: csharp
- FindNearbyEnemy()?.Damage(weaponDamage);
- Rather than:
- .. code-block:: csharp
- FindNode()?.Change(wpnDmg);
- Member variables
- ----------------
- Don't declare member variables if they are only used locally in a method, as it
- makes the code more difficult to follow. Instead, declare them as local
- variables in the method's body.
- Local variables
- ---------------
- Declare local variables as close as possible to their first use. This makes it
- easier to follow the code, without having to scroll too much to find where the
- variable was declared.
- 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 the `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 the 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.
|