C# 스타일 가이드

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

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

참고

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

언어 사양

현재 Godot은 엔진과 예제 소스 코드에 C# 7.0 버전을 사용합니다. 그러므로 신규 버전을 사용할 때는 C# 7.1 이상에서만 지원하는 기능이 섞이지 않도록 주의해야 합니다.

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

서식(Formatting)

일반적인 가이드라인

  • 줄 바꿈을 할 때 CRLF나 CR이 아니라 라인피드 (LF) 문자를 사용해야 합니다.

  • csproj 파일을 제외한 각 파일의 끝 부분에 라인피드 문자 하나를 삽입하십시오.

  • 바이트 순서 표식 BOM 없이 UTF-8 인코딩을 사용하십시오.

  • 들여쓰기를 할 때 탭 대신 4개의 스페이스 문자 를 사용합니다 (이를 "소프트 탭" 이라고 합니다).

  • 한 줄에 글자가 100자를 초과하는 경우 여러 줄로 나누는 것을 고려하십시오.

줄 바꿈 및 공백 줄

일반적인 들여쓰기 규칙으로, Allman Style을 따라 제어문의 중괄호를 그 다음 줄 같은 깊이에 쓰는 것을 권장합니다:

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

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

  • using 문 목록 이후.

  • 메서드, 속성, 그리고 내부 타입 선언 사이.

  • At the end of each file.

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

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

  • {, 괄호 열기 이후.

  • }, 괄호 닫기 이전.

  • 여러 줄에 걸친 주석 혹은 한 줄 짜리 주석 이후.

  • 다른 공백 줄과 인접한 경우.

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(람다 화살표) 주변.

  • 한 줄 주석 상징 (//)이후, 주석이 코드 뒤의 줄 마지막에 위치한 경우 상징의 앞에도 공백을 넣습니다.

공백을 사용하지 마세요:

  • 타입 캐스트 괄호 이후.

  • 한 줄 이니셜라이저 중괄호 안.

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

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

명명 규칙

private 멤버 변수를 제외한 모든 네임스페이스, 즉 타입 이름과 멤버 레벨 식별자 (예: 메서드, 속성, 상수, 이벤트)에 PascalCase 를 사용합니다:

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

        public float CurrentSpeed { get; set; }

        protected int HitPoints;

        private void CalculateWeaponDamage()
        {
        }
    }
}

모든 다른 식별자 (예: 지역 변수, 메서드 인수)에 camelCase를 사용하고, private 멤버 변수의 접두사로 언더스코어(_)를 사용합니다 (이전에 설명했듯이 메서드나 속성에는 해당하지 않습니다):

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

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

    targetFound?.Hit(attackStrength);
}

두 글자로 구성된 두문자어는 예외입니다, UI 같은 것으로, PascalCase가 쓰이는 곳이면 대문자로 써야 하고, 그렇지 않다면 소문자를 써야 합니다.

id 는 두문자어가 아닙니다, 따라서 일반적인 식별자로 취급해야 합니다:

public string Id { get; }

public UIManager UI
{
    get { return uiManager; }
}

string strTextfloat fPower 처럼 타입 이름을 식별자의 접두사로 사용하는 것은 보통 권장되지 않지만, 예외적으로 인터페이스는 반드시 대문자 알파벳 I 를 접두사로 사용해야 합니다. IInventoryHolderIDamageable 이 해당됩니다.

마지막으로 알아보기 쉬운 이름을 고르고 가독성에 해를 끼칠 정도로 이름을 축약하는 것은 피하십시오.

예를 들어, 근처의 적을 찾고 무기로 공격하는 코드를 짜고 싶다면 이렇게 하는 게 좋습니다:

FindNearbyEnemy()?.Damage(weaponDamage);

이것보다는 말이죠:

FindNode()?.Change(wpnDmg);

멤버 변수

메서드에서 지역적으로만 사용되는 경우 멤버 변수를 선언하지 마세요. 코드를 따라가기 더 어렵게 만들기 때문입니다. 대신 메서드 본문에서 지역 변수로 선언하세요.

지역 변수(Local Variables)

지역 변수를 처음 사용할 때와 최대한 가깝게 선언하세요. 이렇게 하면 변수가 선언된 위치를 찾기 위해 너무 많이 스크롤하지 않고도 코드를 더 쉽게 따라갈 수 있습니다.

암시적 타입 지역 변수

지역 변수의 선언에 암시적 타입 (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;

기타 고려 사항

  • 명시적 접근 모디파이어를 사용하세요.

  • non-private 멤버 변수 대신 속성(property)을 사용하세요.

  • 이 순서로 제어자를 사용하세요: public/protected/private/internal/virtual/override/abstract/new/static/readonly.

  • 꼭 필요하지 않다면 fully-qualified name 및 this. 접두사를 사용해 멤버를 호출하는 것을 피하십시오.

  • 사용되지 않은 using 문 및 불필요한 괄호를 지우십시오.

  • 타입에 기본적으로 초기화된 값을 사용하지 않고 다시 초기화 하는 것을 권장합니다.

  • 코드를 더 간결하게 만들기 위해 무효 조건 연산자나 타입 이니셜라이저를 사용하는 것을 고려해보세요.

  • 값이 다른 타입의 가능성이 있을 때 안전한 캐스트를 사용하고, 그렇지 않으면 직접 캐스트를 사용하세요.