C# 风格指南

对于每个项目来说,拥有定义良好且一致的编码约定都是很重要的,而godot也不例外。

此页面包含一个编码样式指南,随后是Godot本身的开发人员和贡献者。因此,它主要针对那些希望为项目做出贡献的人,但是由于本文中提到的公约和准则是语言用户最广泛采用的,我们鼓励您这样做,特别是如果您还没有这样的指南。

注解

本文绝不是关于如何遵循标准编码约定或最佳实践的详尽指南。如果您不确定此处未涉及的方面,请参阅更全面的文档,例如 C# Coding ConventionsFramework Design Guidelines .

语言规范

Godot目前使用 C# version 7.0 在它的引擎和示例源代码中。因此,在我们转到新版本之前,必须注意避免混合仅在C# 7.1或更高版本中可用的语言功能。

有关不同版本的C# 功能的详细信息,请参阅 What's New in C# .

格式设置约定

  • 使用换行符( LF )要换行的字符,而不是CRLF或CR。

  • 使用 UTF-8 不带的编码 byte order mark .

  • 使用 4个空格 而不是用于缩进的制表符(称为“软制表符”)。

  • 如果一行超过100个字符,请考虑将它分成若干行。

换行符和空行

对于一般缩进规则,请遵循 the "Allman Style" 建议将与控制语句关联的大括号放在下一行,缩进到同一级别:

// Use this style:
if (x > 0)
{
    DoSomething();
}

// NOT this:
if (x > 0) {
    DoSomething();
}

但是,您可以选择省略括号内的换行符:

  • 对于简单属性访问器。

  • 对于简单对象、数组或集合初始值设定项。

  • 用于抽象自动属性、索引器或事件声明。

// 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};
        }
    }
}

插入空行:

  • 在列出 using 声明。

  • 方法、属性和内部类型声明之间。

  • 在每个文件的末尾。

字段和常量声明可以根据相关性分组在一起。在这种情况下,考虑在组之间插入一个空行,以便于阅读。

避免插入空行:

  • {{ ,开口撑。

  • 之前 }} ,闭合支架。

  • 在注释块或单行注释之后。

  • 与另一空行相邻。

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()
    {
    }
}

使用空格

插入空格:

  • 关于二元和三元运算符。

  • 在左括号和之间 ifforforeachcatchwhilelockusing 关键词。

  • 在单行访问器块之前和之内。

  • 在单行访问器块中的访问器之间。

  • 在一个不在行尾的逗号之后。

  • 在a中的分号之后 for 语句。

  • 在一行中的冒号之后 case 语句。

  • 在类型声明中的冒号周围。

  • 围绕一个lambda箭头。

  • 在单行注释符号之后 (// ,如果在行尾使用,则在行尾使用。

不要使用空格:

  • 在类型转换括号之后。

  • 在单行初始值设定项大括号内。

根据上面提到的一些约定,下面的示例显示了空间的正确使用:

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.
    }
}

命名约定

使用 PascalCase 对于所有命名空间、类型名和成员级标识符(即方法、属性、常量、事件),除了专用字段:

namespace ExampleProject
{
    public class PlayerCharacter
    {
        public const float DefaultSpeed = 10f;

        public float CurrentSpeed { get; set; }

        protected int HitPoints;

        private void CalculateWeaponDamage()
        {
        }
    }
}

使用 骆驼壳 对于所有其他标识符(即局部变量、方法参数),并使用下划线 (_ )作为私有字段的前缀(但不用于方法或属性,如上所述):

private Vector3 _aimingAt; // Use a `_` prefix for private fields.

private void Attack(float attackStrength)
{
    Enemy targetFound = FindTarget(_aimingAt);

    targetFound?.Hit(attackStrength);
}

首字母缩略词有一个例外,它由两个字母组成,比如 UI 它应该用大写字母写,而pascalcase应该用小写字母写。

注意 idnot 一个缩写词,因此它应该被视为一个正常的标识符:

public string Id { get; }

public UIManager UI
{
    get { return uiManager; }
}

通常不鼓励使用类型名作为标识符的前缀,例如 string strTextfloat fPower 例如。但是,对于接口,会有一个例外,即 应该 实际上,有一个大写字母 I 以他们的名字为前缀,比如 IInventoryHolderIDamageable .

最后,考虑选择描述性名称,如果它影响可读性,不要尝试过多地缩短名称。

例如,如果您想编写代码来查找附近的敌人并用武器攻击它,请选择:

FindNearbyEnemy()?.Damage(weaponDamage);

而不是:

FindNode()?.Change(wpnDmg);

隐式类型的局部变量

考虑使用隐式类型 (var )用于声明局部变量,但要这样做 只有在类型明显时 从任务的右侧:

// 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;

其他注意事项

  • 使用显式访问修饰符。

  • 使用属性而不是非私有字段。

  • 按以下顺序使用修饰符: public/protected /`` private`/`` internal``/`` virtual``/`` override``/`` abstract``/`` new``/`` static``/`` readonly``。

  • 避免使用完全限定名或 this. 不需要时为成员添加前缀。

  • 移除未使用的 using 语句和不必要的括号。

  • 考虑省略类型的默认初始值。

  • 考虑使用空条件运算符或类型初始值设定项使代码更紧凑。

  • 如果值可能是其他类型,请使用安全强制转换,否则使用直接强制转换。