C# Code Style 가이드

이현석·2023년 4월 27일
0

C#

목록 보기
2/2

SK Hynix systemic의 C# 스타일 가이드


이 스타일 가이드는 SK Hynix systemic의 IT 운영/개발에 사용할 목적이며, Google/MS/Kakao/Naver 등 회사의 스타일을 참조하여 작성하였습니다.

C# Code Convention


Naming 규칙

명명 규칙은 Microsoft의 C# 명명 지침을 따릅니다 . Microsoft의 명명 지침이 지정되지 않은 경우(예: 개인 및 지역 변수) CoreFX C# 코딩 지침 에서 규칙을 가져옵니다.

규칙 요약:

Code

  • 클래스, 메서드, 열거형(enum), public 필드, public 속성, 네임스페이스의 이름: PascalCase.
  • 지역 변수 이름, 매개변수: camelCase.
  • private, protected, 내부 및 내부 protected 필드 및 속성의 이름: _camelCase.
  • 명명 규칙은 const, static, readonly 등과 같은 제어자의 영향을 받지 않습니다.
  • "단어"는 머릿말을 포함하여 내부 공백 없이 작성된 모든 것입니다. 예를 들어MyRPC대신MyRpc.
  • 인터페이스 이름은 I로 시작합니다 (예: ) IInterface.

파일

  • 파일 이름과 디렉토리 이름은 PascalCase 예를 들어 MyFile.cs.
  • 가능한 경우 파일 이름은 파일의 기본 클래스 이름과 동일해야 합니다 예: MyClass.cs.
  • 일반적으로 파일당 하나의 코어(주요 동작) 클래스를 선호합니다.

Organization

  • 제어자는 다음 순서로 발생합니다. public protected internal private new abstract virtual override sealed static readonly extern unsafe volatile async.
  • 네임스페이스 using선언은 어떤 네임스페이스보다 맨 위에 옵니다. using import 순서는 System import 제외하고 알파벳순입니다.
  • 클래스 member 순서:
    • 클래스는 다음 순서로 그룹화합니다.
      • 중첩된 클래스, 열거형(enums), 대리자(delegates) 및 이벤트
      • Static, const 및 readonly 필드.
      • 필드 및 속성.
      • 생성자와 종료자.
      • 메소드.
    • 각 그룹 내에서 요소는 다음 순서를 따라야 합니다.
      • Public.
      • Internal.
      • Protected internal.
      • Protected.
      • Private.
    • 가능한 경우 인터페이스 구현을 함께 그룹화하십시오.

공백 규칙

Google Java 스타일 참고

  • 라인당 최대 하나의 선언문.
  • 선언문당 최대 하나의 할당입니다.
  • 탭 없이 2칸 들여쓰기.
  • Column 제한: 100.
  • 중괄호를 열기 전에 줄 바꿈이 없습니다.
  • 닫는 중괄호와 else 사이에 줄 바꿈이 없습니다.
  • 옵션인 경우에도 중괄호를 사용합니다.
  • if/ for/ while 등과 콤마 뒤에 공백이 있습니다.
  • 여는 괄호 뒤나 닫는 괄호 앞에 공백이 없습니다.
  • 단항 연산자와 해당 피연산자 사이에 공백이 없습니다. 연산자와 다른 모든 연산자의 각 피연산자 사이에 공백 하나.
  • Microsoft의 C# 서식 지정 도구와의 호환성을 위해 약간 수정하여 Google C++ 스타일 지침에서 개발된 줄 바꿈:
    • 일반적으로 줄 연속은 4칸 들여쓰기됩니다.
    • 중괄호로 줄 바꿈(예: 목록 이니셜라이저, 람다, 객체 이니셜라이저 등)은 연속으로 간주되지 않습니다.
    • 함수 정의 및 호출의 경우 인수가 모두 한 줄에 맞지 않으면 여러 줄로 나누어 각 후속 줄을 첫 번째 인수에 맞춰야 합니다. 이를 위한 공간이 충분하지 않은 경우 인수는 네 칸 들여쓰기로 후속 줄에 대신 배치될 수 있습니다. 아래 코드 예제는 이를 보여줍니다.

예시

using System;                                       // `using`은 네임스페이스 외부의 맨 위에 위치합니다.

namespace MyNamespace {                             // Namespaces = PascalCase.
                                                    // 네임스페이스 뒤에 들여쓰기.
  public interface IMyInterface {                   // Interfaces start with 'I'
    public int Calculate(float value, float exp);   // Methods = PascalCase
                                                    // ...쉼표 뒤의 공백.
  }

  public enum MyEnum {                              // Enumerations = PascalCase.
    Yes,                                            // Enumerators = PascalCase.
    No,
  }

  public class MyClass {                            // Classes = PascalCase.
    public int Foo = 0;                             // Public member variables =
                                                    // PascalCase.
    public bool NoCounting = false;                 // 필드 초기화를 권장합니다.
    private class Results {
      public int NumNegativeResults = 0;
      public int NumPositiveResults = 0;
    }
    private Results _results;                       // Private member variables =
                                                    // _camelCase.
    public static int NumTimesCalled = 0;
    private const int _bar = 100;                   // const는 명명 규칙에 영향을 미치지 않습니다.
    private int[] _someTable = {                    // 컨테이너 이니셜라이저는 2를 사용
      2, 3, 4,                                      // 공백 들여쓰기.
    }

    public MyClass() {
      _results = new Results {
        NumNegativeResults = 1,                     // 개체
초기화는 2칸 들여쓰기 사용
        NumPositiveResults = 1,                   
      };
    }

    public int CalculateValue(int mulNumber) {      // 중괄호 열기
전에 줄 바꿈은 없음.
      var resultValue = Foo * mulNumber;            // 지역변수 = camelCase
      NumTimesCalled++;
      Foo += _bar;

      if (!NoCounting) {                            // 단항 연산자 뒤에는 공백이 없고, ‘if‘ 뒤에 한칸 공백
        if (resultValue < 0) {                      // option 문의
경우에도 중광호를 사용하고
                                                    // 비교연산자 주위에 공백을 둡니다.
          _results.NumNegativeResults++;
        } else if (resultValue > 0) {               // 중괄호와 else 사이에 줄 바꿈이 없습니다.
          _results.NumPositiveResults++;
        }
      }

      return resultValue;
    }

    public void ExpressionBodies() {
      //간단한 람다식의 경우 가능하면 한줄에 맞추고 대괄호, 중괼호는 필요하지 않습니다.
      Func<int, int> increment = x => x + 1;

      // 닫는 중괄호는 여는 중괄호를 포함하는 행의 첫번째 문자에 정렬 됩니다.
      Func<int, int, long> difference1 = (x, y) => {
        long diff = (long)x - y;
        return diff >= 0 ? diff : -diff;
      };

      // 연속 줄바꿈 후에 정의 하는 경우 전체 본문을 들여쓰기 합니다.
      Func<int, int, long> difference2 =
          (x, y) => {
            long diff = (long)x - y;
            return diff >= 0 ? diff : -diff;
          };

      // 인라인 람다 인자도 이런 규칙을 따릅니다.
      // 람다를 포함하는 경우 인자 그륩 앞에 산행 개행을 선호 합니다.
      CallWithDelegate(
          (x, y) => {
            long diff = (long)x - y;
            return diff >= 0 ? diff : -diff;
          });
    }

    void DoNothing() {}                             // 빈 블락은 간결 할 수 있습니다.

    // 가능하면 새 Line에 첫 번째 임수와 정렬 하여 다른 인자를 맞춥니다.
    void AVeryLongFunctionNameThatCausesLineWrappingProblems(int longArgumentName,
                                                             int p1, int p2) {}

    // 인자 라인을 첫 번째 인자와 정렬 하는 것이 적합 하지 않거나 읽기 어려운 경우
    //  모든 인자를 새 줄에 4칸 들여쓰기오 묶습니다.
    void AnotherLongFunctionNameThatCausesLineWrappingProblems(
        int longArgumentName, int longArgumentName2, int longArgumentName3) {}

    void CallingLongFunctionName() {
      int veryLongArgumentName = 1234;
      int shortArg = 1;
      //가능하면 새 Line에 첫 번째 임수와 정렬 하여 다른 인자를 맞춥니다.
      AnotherLongFunctionNameThatCausesLineWrappingProblems(shortArg, shortArg,
                                                            veryLongArgumentName);
      //인자 라인을 첫 번째 인자와 정렬 하는 것이 적합 하지 않거나 읽기 어려운 경우
      // 모든 인자를 새 줄에 4칸 들여쓰기오 묶습니다.
      AnotherLongFunctionNameThatCausesLineWrappingProblems(
          veryLongArgumentName, veryLongArgumentName, veryLongArgumentName);
    }
  }
}

C# 코딩 규칙


상수

  • const로 만들 수 있는 변수와 필드는 항상 const로 만들어야 합니다..
  • const불가능 하다면 readonly는 적절한 대안이 될 수 있습니다.
  • 매직 넘버보다 명명된 상수를 선호합니다.

IEnumerable vs IList vs IReadOnlyList

  • 입력의 경우 가능한 한 가장 제한적인 컬렉션 유형을 사용합니다. 예를 들어 IReadOnlyCollection/ IReadOnlyList/ IEnumerable입력이 변경 불가능해야 하는 경우 메서드에 대한 입력으로 사용합니다.
  • 출력의 경우 반환된 컨테이너의 소유권을 소유자에게 전달하는 경우 IEnumerable보다 IList를 선호합니다. 소유권을 이전하지 않는 경우 가장 제한적인 옵션을 선호합니다.

Generators vs Containers

  • 다음 사항을 염두에 두고 최선의 판단을 내리세요.

    • 생성기 코드는 종종 컨테이너를 채우는 것보다 가독성이 떨어집니다.
    • 결과가 느리게 처리되는 경우(예: 모든 결과가 필요하지 않은 경우) 생성기 코드의 성능이 향상될 수 있습니다.
    • 컨테이너로 직접 변환되는 생성기 코드는 ToList() 컨테이너를 직접 채우는 것보다 성능이 떨어집니다.
    • 여러 번 호출되는 생성기 코드는 컨테이너를 여러 번 반복하는 것보다 상당히 느립니다.

    Generators와 Containers의 정의 Link

profile
溫故知新

0개의 댓글