C# 스타일 가이드

잘 정의되고 일관된 코딩 규칙을 정하는 것은 모든 프로젝트에 중요하며 Godot도 마찬가지입니다.

이 페이지는 코딩 스타일 가이드로, Godot의 개발자나 기여자들이 지켜야 하는 문서들입니다. 따라서 이 문서는 주로 프로젝트에 기여하는 사람들이 대상이지만, 여기에서 말하는 규칙이나 가이드 라인은 프로그래밍 언어 사용자들에 의해 가장 널리 채택된 것이고 우리는 이를 따라가길 권장합니다, 특히 이러한 가이드를 아직 찾지 못했다면 말이죠.

주석

이 문서는 표준 코딩 규칙이나 최고의 방법에 관한 포괄적인 가이드가 아닙니다. 혹시 다루지 않은 불확실한 면이 있다면, C# 코딩 규칙 이나 명명 지침에서 더 포괄적인 문서를 참고하세요.

언어 사양

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.

다른 버전에서 C# 기능에 대한 더 자세한 정보는 `C#의 새로운 기능<https://docs.microsoft.com/ko-kr/dotnet/csharp/whats-new/>`_을 참고하세요.

형식 규칙

  • Use line feed (LF) characters to break lines, not CRLF or CR.
  • Use UTF-8 encoding without a 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.

줄 바꿈 및 공백 줄

For a general indentation rule, follow the "Allman Style" which recommends placing the brace associated with a control statement on the next line, indented to the same level:

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

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

그러나, 중괄호 안에 줄 바꿈을 생략할 수 있습니다:

  • 간단한 속성 접근자를 위해.
  • 간단한 객체, 배열, 혹은 컬렉션 이니셜라이저를 위해.
  • 추상적 auto 속성, 인덱서, 혹은 이벤트 선언을 위해.
// 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};
        }
    }
}

다음 경우에 공백 줄을 넣습니다:

  • After a list of using statements.
  • 메서드, 속성, 그리고 내부 타입 선언 사이.
  • At the end of each file.

공백과 상수 선언은 관련성에 따라 함께 묶을 수 있습니다. 이 경우, 가독성을 위해, 묶음 사이에 공백 줄을 넣는 것을 고려해볼 수 있습니다.

다음 경우에 공백 줄을 삽입하는 것을 피하세요:

  • {, 괄호 열기 이후.
  • }, 괄호 닫기 이전.
  • After a comment block or a single-line comment.
  • 다른 공백 줄과 인접한 경우.
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()
    {
    }
}

공백 사용하기

다음 경우에 공백을 넣습니다:

  • 이진 및 삼항 연산자 주변.
  • Between an opening parenthesis and if, for, foreach, catch, while, lock or using keywords.
  • 한 줄 접근자 블록 전이나 앞.
  • 한 줄 접근자 블록에서 접근자들 사이.
  • 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.
  • 타입 선언에서 콜론 주변.
  • Lambda arrow(람다 화살표) 주변.
  • After a single-line comment symbol (//), and before it if used at the end of a line.

공백을 사용하지 마세요:

  • 타입 캐스트 괄호 이후.
  • 한 줄 이니셜라이저 중괄호 안.

다음 예제는 위에서 언급한 규칙에 따라 적절한 공백의 사용을 보여줍니다:

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

명명 규칙

Use PascalCase for all namespaces, type names and member level identifiers (i.e. methods, properties, constants, events), except for private fields:

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):

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:

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.

마지막으로 서술적인 이름을 고르는 것은 생각하되 너무 축약해서 가독성에 해를 끼치게 해서는 안됩니다.

For instance, if you want to write code to find a nearby enemy and hit it with a weapon, prefer:

FindNearbyEnemy()?.Damage(weaponDamage);

Rather than:

FindNode()?.Change(wpnDmg);

암시적 형식 지역 변수

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:

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

기타 고려 사항

  • 명시적 액세스 모디파이어를 사용하세요.
  • 비공개 영역 대신 속성을 사용하세요.
  • 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.
  • 코드를 더 간결하게 만들기 위해 null 조건의 연산자나 타입 이니셜라이저를 사용하는 것을 고려해보세요.
  • 값이 다른 타입의 가능성이 있을 때 안전한 캐스트를 사용하고, 그렇지 않으면 직접 캐스트를 사용하세요.