C# 코딩 표준

이 문서는 아래 사이트로 이동되었습니다. 최신 문서를 확인해주세요. https://wiki.gsti.co.kr/dev-guide/csharp/coding-convention

기본 원칙

  1. 가독성을 최우선으로 삼는다. (대부분의 경우 코드는 그 자체가 문서의 역할을 해야 함)

  2. 정말 합당한 이유가 있지 않는 한, 통합개발환경(IDE)의 자동 서식을 따른다. (비주얼 스튜디오의 “Ctrl + K + D” 기능)

  3. 본 코딩 표준을 따라 잘 짜여진 기존의 코드에서 배운다.

참조문서

기타

좋은 코딩을 위한 13 가지 간단한 규칙

https://mingrammer.com/translation-13-simple-rules-for-good-coding/

명명 규칙과 스타일

  • 클래스와 구조체의 이름은 파스칼 표기법을 따른다.

class PlayerManager;
struct PlayerData;

  • 지역 변수 그리고 함수의 매개 변수의 이름은 카멜 표기법을 따른다.

public void SomeMethod(int someParameter)
{
  int someNumber;
  int id;
}

  • 메서드 이름은 기본적으로 동사(명령형)+명사(목적어)의 형태로 짓는다.

public uint GetAge()
{
    // 함수 구현부...
}

  • 단, 단순히 부울(boolean) 상태를 반환하는 메서드의 동사 부분은 최대한 Is, Can, Has, Should를 사용하되 그러는 것이 부자연스러울 경우에는 상태를 나타내는 다른 3인치 단수형 동사를 사용한다.

public bool IsAlive(Person person);
public bool Has(Person person);
public bool CanAccept(Person person);
public bool ShouldDelete(Person person);
public bool Exists(Person person);

  • 아래에 제시된 예를 제외하곤 모든 메서드의 이름은 파스칼 표기법을 따른다.

public uint GetAge()
{
    // 함수 구현부...
}

  • 상수의 이름은 모두 대문자로 하되 밑줄로 각 단어를 분리한다.

const int SOME_CONSTANT = 1;

  • 상수로 사용하는 개체형 변수에는 static readonly를 사용한다.

  • static readonly 변수는 모두 대문자로 하되 밑줄로 각 단어를 분리한다.

public static readonly MY_CONST_OBJECT = new MyConstClass();

  • 초기화 후 값이 변하지 않는 변수는 readonly로 선언한다.

public class Account
{
    private readonly string _Password;

    public Account(string password)
    {
        _Password = password;
    }
}

  • 네임스페이스의 이름은 파스칼 표기법을 따른다.

namespace System.Graphics

  • 부울(boolean) 프로퍼티는 앞에 Is, Has, Can, Should 중에 하나를 붙인다.

public bool IsFired { get; private set; }
public bool HasChild { get; private set; }
public bool CanModal { get; private set; }
public bool ShouldRedirect { get; private set; }

  • 인터페이스를 선언할 때는 앞에 I를 붙인다.

interface ISomeInterface;

  • private 멤버 변수명은 앞에 '_'(underline)을 붙이고 파스칼 표기법을 따른다

public class Employee
{
    public int DepartmentID { get; set; } // public 프로퍼티
    private int _Age; // private 멤버 변수
}

  • 값을 반환하는 함수의 이름은 무엇을 반환하는지 알 수 있게 짓는다.

public uint GetAge();

  • 단순히 반복문에 사용되는 변수가 아닌 경우엔 i, e 같은 변수명 대신 index, employee 처럼 변수에 저장되는 데이터를 한 눈에 알아볼 수 있는 변수명을 사용한다.

  • 뒤에 추가적인 단어가 오지 않는 경우 줄임말은 모두 대문자로 표기한다.

public int OrderID { get; private set; }
public int HttpCode { get; private set; }

  • getter와 setter 대신 프로퍼티를 사용한다.

// 올바른 방식 :
public class Employee
{
    public string Name { get; set; }
}

// 틀린 방식 :
public class Employee
{
    private string mName;
    public string GetName();
    public string SetName(string name);
}

  • 탭(tab)은 비주얼 스튜디오 기본값을 사용하며, 비주얼 스튜디오를 사용하지 않을 시 띄어쓰기 4칸을 탭으로 사용한다.

  • 지역 변수를 선언할 때는 그 지역 변수를 사용하는 코드와 동일한 줄에 선언하는 것을 원칙으로 한다.

  • 중괄호( { )를 열 때는 언제나 새로운 줄에 연다.

  • 중괄호 안( { } )에 코드가 한 줄만 있더라도 반드시 중괄호를 사용한다.

if (IsSomething)
{
    return;
}

  • double이 반드시 필요한 경우가 아닌 이상 부동 소수점 값에 f를 붙여준다

float f = 0.5F;

  • 재귀 함수는 이름 뒤에 Recursive를 붙인다.

public void FibonacciRecursive();

  • 클래스 안에서 멤버 변수와 메서드의 등장 순서는 다음을 따른다.

    1. public 멤버변수/프로퍼티

    2. internal 멤버변수/프로퍼티

    3. protected 멤버변수/프로퍼티

    4. private 멤버변수

      1. 단, 프로퍼티와 대응하는 private 멤버변수는 프로퍼티 바로 위에 적음

    5. 생성자

    6. public 메서드

    7. Internal 메서드

    8. protected 메서드

    9. private 메서드

  • 대부분의 경우 함수 오버로딩을 피한다.

// 올바른 방식:
public Anim GetAnimByIndex(int index);
public Anim GetAnimByName(string name);

// 틀린 방식:
public Anim GetAnim(int index);
public Anim GetAnim(string name);

  • 클래스는 각각 독립된 소스 파일에 있어야 한다. 단, 작은 클래스 몇 개를 한 파일 안에 같이 넣어두는 것이 상식적일 경우 예외를 허용한다.

  • 파일 이름은 대소문자까지 포함해서 반드시 클래스 이름과 일치해야 한다. public class PlayerAnimation {} PlayerAnimation.cs

  • 여러 파일이 하나의 클래스를 이룰 때(즉, partial 클래스), 파일 이름은 클래스 이름으로 시작하고, 그 뒤에 마침표와 세부 항목 이름을 붙인다. public partial class Human; Human.Head.cs Human.Body.cs Human.Arm.cs

  • 디폴트 매개 변수 대신 함수 오버로딩을 선호한다.

  • 디폴트 매개 변수를 사용하는 경우, null이나 false, 0 같이 비트 패턴이 0인 값을 사용한다.

  • 변수 가리기(variable shadowing)는 허용되지 않는다. 외부 변수가 동일한 이름을 사용중이라면 내부 변수에는 다른 이름을 사용한다.

public class SomeClass
{
    public int Count { get; set; }
    
    public void Func(int count)
    {
        for (int count = 0; count != 10; ++count)
        {
            // count를 사용
        }
    }
}

  • 언제나 System.Collections에 들어있는 컨테이너 대신에 System.Collections.Generic에 들어있는 컨테이너를 사용한다. 순수 배열을 사용하는 것도 괜찮다.

  • var 키워드를 사용하지 않으려 노력한다. 단, 대입문의 우항에서 데이터형이 명확하게 드러나는 경우, 또는 데이터형이 중요하지 않은 경우에는 예외를 허용한다 . IEnumerable에 var를 사용하거나 우항의 new 키워드를 통해 어떤 개체가 생성되는지 알 수 있는 등이 허용되는 경우의 좋은 예이다.

var text = "string obviously";
var age = 28;
var employee = new Employee();

string accountNumber = GetAccountNumber();

  • 싱글턴 패턴 대신에 정적(static) 클래스를 사용한다.

  • async void 대신에 async Task를 사용한다. async void가 허용되는 유일한 곳은 이벤트 핸들러이다.

  • 외부로부터 들어오는 데이터의 유효성은 외부/내부 경계가 바뀌는 곳에서 검증(validate)하고 문제가 있을 경우 내부 함수로 전달하기 전에 반환해 버린다. 이는 경계를 넘어 내부로 들어온 모든 데이터는 유효하다고 가정한다는 뜻이다.

  • 따라서 내부 함수에서 예외(익셉션)를 던지지 않으려 노력한다. 예외는 경계에서만 처리하는 것을 원칙으로 한다.

  • 위 규칙의 예외: enum 형을 switch 문에서 처리할 때 실수로 처리 안 한 enum 값을 찾기 위해 default: 케이스에서 예외를 던지는 것은 허용.

switch (accountType)
{
    case AccountType.Personal:
        return something;
    case AccountType.Business:
        return somethingElse;
    default:
        throw new ArgumentOutOfRangeException(nameof(AccountType));
}

  • 함수의 매개변수로 null을 허용하지 않는 것을 추구한다. 특히 public 함수일 경우 더욱 그러하다.

  • null 매개변수를 사용할 경우 변수명 뒤에 OrNull를 붙인다.

public Anim GetAnim(string nameOrNull)
{
}

  • 함수에서 null을 반환하지 않는 것을 추구한다. 특히 public 함수일 경우 더욱 그러하다. 그러나 때로는 예외를 던지는 것을 방지하기 위해 그래야 할 경우도 있다.

  • 함수에서 null을 반환할 때는 함수 이름 뒤에 OrNull을 붙인다.

public string GetNameOrNull();

  • 한 줄에 변수 하나만 선언한다.

// 틀린 방식:
int counter = 0, index = 0;

// 올바른 방식: 
int counter = 0;
int index = 0;

  • 다음 코드에 나와 있는 것처럼 문자열 보간을 사용하여 짧은 문자열을 연결한다.

string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";

  • foreach 루프의 루프 변수 형식을 결정하기 위해 암시적 형식을 사용하지 않는다.

// 틀린 방식:
foreach (var ch in laugh) 
{
}

// 올바른 방식: 
foreach (char ch in laugh)
{
}

var wordCaptions =
    from baseWordInfos in baseResults.AsEnumerable()
    join customWordInfos in customResults.AsEnumerable()
    on baseWordInfos["word_id"] equals customWordInfos["word_id"] into groupJoin
    from joinResult in groupJoin.DefaultIfEmpty()
    select new
    {
        WordID = baseWordInfos["word_id"],
        WordText = joinResult == null ? baseWordInfos["word_id"] : joinResult["word_id"]
    };

Last updated

Was this helpful?