AgentSkillsCN

04 Unity Csharp Compat

04 Unity C# 兼容性

SKILL.md

04-unity-csharp-compat — Unity C# 문법/언어버전 제한

Status: ACTIVE
AppliesTo: v10
SSOT: this file

Purpose

Unity(UPM/Packages 포함)에서 컴파일 깨짐을 원천 방지하기 위한 C# 문법 및 언어버전 제한 정책을 정의한다.


Policy (정책)

A) 적용 범위 (Scope)

이 정책은 Unity에서 컴파일되는 모든 C# 코드에 적용된다.

적용 대상 경로:

경로설명
framework-cs/upm/**수동 관리 UPM 패키지
framework-cs/apps/UnityExample/Packages/**Unity 최종 패키지
framework-cs/apps/**/Packages/**추가 Unity 앱/샘플 패키지

적용 대상은 수동 코드 + 생성물 모두 포함한다. UPM 패키지 내부의 Samples~/, Templates/ 및 패키지로 복사된 샘플 코드도 동일하게 적용 대상이다.

B) 언어 버전 고정 (Language Level)

Hard Rule:

  • Unity 대상 C# 코드는 C# 8 호환 문법만 사용한다.
  • 최신 C# 기능을 "추측으로" 사용하지 않는다.
  • Unity 버전에 따라 지원되지 않는 문법은 컴파일 실패를 유발한다.

C) 금지 문법 목록 (Forbidden — 발견 시 FAIL)

아래 문법은 Unity C# 적용 범위에서 하드 금지이며, 발견 시 빌드/정책상 FAIL이다.

금지 문법설명예시
Primary constructorclass/struct/record 헤더에 ( 붙는 형태class X(...), struct X(...)
record, record struct레코드 타입record Person(...)
required 멤버필수 속성 한정자required string Name
File-scoped namespace세미콜론으로 끝나는 namespacenamespace X;
global using전역 usingglobal using System;
Target-typed new()타입 생략된 newList<int> x = new();
init accessorinit-only setter{ get; init; }
Collection expression대괄호 컬렉션 생성int[] arr = [1, 2, 3];
List pattern리스트 패턴 매칭x is [1, 2, ..]
Raw string literal삼중 따옴표 문자열"""..."""
Delegate 식별자에 ?delegate 선언의 이름에 ? 붙이기delegate void Handler?(int x)
타입 표기에 ??타입/멤버 선언부에서 ?? 사용Handler??, Action??

원칙: Unity에서 불확실한 최신 문법은 금지한다.

Nullable/Delegate 문법 하드 금지:

  • Delegate 선언에서 식별자(이름)에 ?를 붙이는 것은 문법 오류다. nullable 표기는 참조 사용 위치에서만 의미가 있다.
  • 타입 표기에서 ??가 만들어지는 패턴은 문법 오류다. ??는 표현식 연산자이며 타입/멤버 선언부에 등장하면 컴파일 실패한다.

D) 표현식 vs 선언 규칙 (CS1519 방지)

Hard Rule:

  • ??, ??= 등 null-coalescing 계열은 메서드/표현식 내부에서만 사용한다.
  • 필드/프로퍼티/클래스 본문(멤버 선언 영역)에 "표현식 조합"을 넣는 형태는 금지한다.
  • 애매한 경우 로컬 변수/메서드에서 처리한다.

금지 예시 (delegate 선언에 ? 붙이기):

csharp
// ❌ WRONG - delegate 선언에 ? 붙임
public delegate void MyHandler?(int x);

// ❌ WRONG - 프로퍼티 타입에 ?? 중복
public MyHandler?? OnEvent { get; set; }

올바른 예시:

csharp
// ✅ CORRECT - delegate 선언은 ? 없이
public delegate void MyHandler(int x);

// ✅ CORRECT - nullable 프로퍼티는 타입에 ? 하나만
public MyHandler? OnEvent { get; set; }

// ✅ CORRECT - ?? 는 메서드 내부에서 사용
public void DoSomething()
{
    var handler = OnEvent ?? DefaultHandler;
}

Verification (검증)

금지 패턴 검사 (Hard Gate)

아래 정규식 패턴이 적용 범위 경로에서 1개라도 발견되면 FAIL:

패턴탐지 대상
\bclass\s+\w+\s*\(class primary constructor
\bstruct\s+\w+\s*\(struct primary constructor
\brecord\brecord 타입
\brequired\brequired 멤버
^\s*namespace\s+.*;\s*$file-scoped namespace
\bglobal\s+using\bglobal using
\bnew\s*\(\s*\)\s*;?target-typed new
\binit\s*;init accessor
\bdelegate\b[^{;]*\w+\s*\?\s*\(delegate 식별자에 ? 붙은 경우
\b[A-Za-z_][A-Za-z0-9_]*\s*\?\?\b타입/선언부에서 ?? 패턴

패턴 \b[A-Za-z_][A-Za-z0-9_]*\s*\?\?\b가 false positive를 내면, 해당 코드를 메서드 내부 표현식으로 옮기고 선언부에서 제거한다.

검사 대상 경로:

  • framework-cs/upm/
  • framework-cs/apps/**/Packages/
  • UPM 패키지 내부의 Samples~/ 및 템플릿/샘플 코드도 검사 대상에 포함한다.

DoD (Definition of Done)

  • 적용 범위 경로에서 금지 패턴 발견 시 빌드 FAIL
  • 모든 Unity C# 코드가 C# 8 호환 문법만 사용

Examples (예시)

좋은 예

csharp
// ✅ Block-scoped namespace
namespace Devian
{
    // ✅ 일반 클래스 선언
    public sealed class NetClient
    {
        private readonly INetRuntime _runtime;
        
        // ✅ nullable 프로퍼티
        public Action<int>? OnError { get; set; }
        
        // ✅ 생성자
        public NetClient(INetRuntime runtime)
        {
            _runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
        }
    }
}

나쁜 예

csharp
// ❌ File-scoped namespace
namespace Devian;

// ❌ Primary constructor
public class NetClient(INetRuntime runtime)
{
}

// ❌ Target-typed new
private readonly List<int> _list = new();

// ❌ Init accessor
public string Name { get; init; }

// ❌ Required member
public required string Id { get; set; }

asmdef precompiledReferences 정책 (Hard Rule)

정책

Unity의 .asmdef 파일에서 precompiledReferences로 선언된 DLL은 실제로 프로젝트에 존재해야 한다.

상태결과
DLL 파일 존재✅ 정상 빌드
DLL 파일 없음 (meta만 존재)❌ 빌드 실패
DLL 파일 없음 (meta도 없음)❌ 빌드 실패

편의성 우선 정책

이 프레임워크는 "DLL 없으면 빌드 실패"를 허용하는 정책을 채택했다.

이유:

  • Devian.Core.asmdefGoogle.Protobuf.dllprecompiledReferences로 선언한다
  • Protobuf 기능이 필요한 경우 해당 DLL이 필수이다
  • DLL이 없는 상태에서 컴파일 실패는 의도된 동작이다

사용자 책임

항목설명
DLL 준비Google.Protobuf.dll을 프로젝트에 포함해야 함
경로Assets/Plugins/ 또는 Unity가 인식하는 위치
.gitignoreDLL을 ignore했다면 clone 후 수동 복사 필요

참고: 이 정책은 skills/devian-core/11-core-serializer-protobuf/SKILL.md의 "Unity Google.Protobuf.dll 정책"과 연계된다.


Reference

  • SSOT: skills/devian-core/03-ssot/SKILL.md
  • Protobuf DLL 정책: skills/devian-core/11-core-serializer-protobuf/SKILL.md
  • 적용 대상: framework-cs/upm/, framework-cs/apps/**/Packages/