순환 참조를 공유 계약 어셈블리로 분리해 단방향 의존성으로 바꾼다.
순환 참조를 공유 계약 어셈블리로 분리해 단방향 의존성으로 바꾼다. 그림 크게 보기

오류 문구보다 먼저 참조 그래프를 그립니다

asmdef는 폴더의 스크립트를 별도 어셈블리로 묶습니다. 한 어셈블리에서 다른 어셈블리의 타입을 쓰면 사용하는 쪽이 제공하는 쪽을 참조해야 합니다. Core → UI와 UI → Core가 동시에 생기면 순환 참조입니다. 참조를 더 추가해 해결할 수 없고, Unity 6.0과 6.6 모두 순환 참조를 허용하지 않습니다.

종이에 각 asmdef 이름을 상자로 적고 화살표를 사용자 → 타입 제공자 방향으로 그려 보세요. 오류 메시지에 이름이 나온 두 어셈블리만 연결해도 순환이 보이는 경우가 많습니다.

Game.UI ───────▶ Game.Core
   ▲                 │
   └─────────────────┘  // 반대 참조가 순환을 만든다

참조 누락이면 사용하는 쪽에 추가합니다

예를 들어 Game.UI 코드가 Game.Core의 InventoryService를 사용한다면 Game.UI.asmdef에서 Game.Core를 참조해야 합니다. Unity 6.6에서는 Game.UI의 Assembly Definition을 선택해 Inspector의 **Assembly Definition References**에서 +를 누르고 Game.Core를 고릅니다. 참조를 제공자 쪽에 거꾸로 추가하지 마세요.

샘플 코드는 참조 방향을 보여 줍니다. 실제 프로젝트에서는 두 스크립트를 Unity가 각각의 asmdef에 포함하는 폴더에 두고 Unity Editor에서 컴파일 결과를 확인하세요.

// Game.Core assembly
namespace Quest.Core
{
    public sealed class InventoryService
    {
        public bool HasItem(string itemId) => itemId == "silver-key";
    }
}

// Game.UI assembly; Game.UI.asmdef references Game.Core
namespace Quest.UI
{
    using Quest.Core;
    public sealed class ChestPanel
    {
        private readonly InventoryService inventory;
        public ChestPanel(InventoryService inventory) => this.inventory = inventory;
        public bool CanOpen() => inventory.HasItem("silver-key");
    }
}

양쪽이 서로의 타입을 써야 하면 계약을 분리합니다

UI가 Core를 쓰면서 Core가 UI의 콜백 타입을 쓰면 두 책임이 맞물린 상태입니다. 양쪽이 함께 쓰는 인터페이스나 데이터 타입을 Game.Contracts 같은 작은 어셈블리로 옮기고, 두 어셈블리가 그 계약만 참조하게 만드세요. 런타임 핵심과 화면 계층을 합칠 수 있다면 서로 참조하는 클래스를 같은 어셈블리에 두는 것도 공식 문서가 안내하는 해결법입니다.

가능하면 Core는 UI를 알지 못하도록 두고, UI가 Core의 public API를 호출하게 합니다. 콜백이 필요하면 계약 어셈블리에 인터페이스를 두고 Core가 그 인터페이스를 받도록 의존성을 뒤집습니다. 참조를 끊을 타입을 고르기 어렵다면 서로 같이 바뀌는 기능인지 먼저 확인하세요.

Game.UI ─────▶ Game.Core
   │               │
   └──────▶ Game.Contracts ◀──────┘

Game.Core ──X──▶ Game.UI   // 이 화살표는 만들지 않는다

Assembly-CSharp 경계도 확인합니다

Assembly-CSharp는 폴더 규칙으로 만들어지는 predefined assembly입니다. Unity 6.0과 6.6의 참조 매뉴얼은 커스텀 asmdef에서 predefined assembly를 참조할 수 없다고 설명합니다. 반대로 기본 설정에서 predefined assembly는 Auto Referenced가 켜진 asmdef를 참조할 수 있습니다. 이 설정은 asmdef끼리 서로의 참조를 자동 생성하지 않습니다.

따라서 asmdef 바깥 폴더의 스크립트가 asmdef 안 타입을 쓸 수 있는데, asmdef 안 스크립트가 Assembly-CSharp에 둔 타입을 못 찾는다면 스크립트 위치가 경계 양쪽에 섞였는지 확인하세요. 서로 함께 써야 하는 타입을 asmdef 아래로 옮기거나, 명시적인 공통 계약 어셈블리를 만드세요.

고친 뒤에는 같은 오류 경로만 다시 확인합니다

asmdef 이름과 참조가 올바른데도 타입을 찾지 못하면 스크립트가 어느 asmdef 폴더에 포함되는지, 플랫폼 제한이나 define constraint 때문에 해당 어셈블리가 현재 구성에서 제외됐는지 확인하세요. Auto Referenced만 켜서 asmdef 간 참조를 해결하려 하지는 마세요.

  1. 콘솔에서 첫 asmdef 오류와 거기에 적힌 어셈블리 이름을 기록합니다.
  2. 각 asmdef에서 **Assembly Definition References**를 열고 실제 참조 방향을 표로 적습니다.
  3. 누락이면 사용자가 제공자를 참조하게 합니다. 순환이면 공통 계약 추출, 한 방향 의존, 또는 같은 어셈블리로 합치기 중 하나를 적용합니다.
  4. Assembly-CSharp 타입을 커스텀 asmdef에서 요구하는 화살표가 남지 않았는지 봅니다.
  5. Unity가 컴파일한 뒤 같은 오류가 사라졌는지 확인하고, 다음 새 오류는 별도 의존성으로 다룹니다.
검증 범위

공식 문서 대조

검증일

Unity 6.0과 6.6 공식 어셈블리 참조 문서를 대조했다. 이 글은 문서 근거로 만든 예시이며 Unity Editor 컴파일 재현을 포함하지 않는다.