본문으로 건너뛰기

Caffeine.Generators API

개요

Caffeine.Generators는 Roslyn Source Generator 기반의 컴파일 타임 코드 생성 패키지입니다. [Packet] 어트리뷰트가 붙은 클래스에 대해 고성능 직렬화 메서드를 자동으로 생성하여, 반복적인 보일러플레이트 코드를 제거하고 Zero-Allocation 아키텍처를 지원합니다.

Caffeine 내 역할

드라이버 통신 패킷, 브릿지 IPC 메시지 등 반복적인 직렬화 로직을 Source Generator로 자동 생성합니다.

기본 정보

항목
패키지NEXCODE.Caffeine.Generators
타겟 프레임워크netstandard2.0
의존성Microsoft.CodeAnalysis.CSharp
Generator 클래스PacketSourceGenerator
생성 파일 패턴{ClassName}_Packet.g.cs

설치

<ItemGroup>
<!-- Roslyn Source Generator는 Analyzer 경로로 참조 -->
<ProjectReference Include="..\Caffeine.Generators\Caffeine.Generators.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>

NuGet 배포 버전 사용 시:

dotnet add package NEXCODE.Caffeine.Generators
<PackageReference Include="NEXCODE.Caffeine.Generators" Version="2.0.*">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

PacketSourceGenerator

동작 원리

  1. 컴파일 타임에 [Packet] 어트리뷰트가 붙은 partial class를 탐색
  2. 해당 클래스에 대해 {ClassName}_Packet.g.cs 파일 생성
  3. 생성된 파일에 ToBytesOptimized() 등의 직렬화 메서드 추가

사용법

// 1. 클래스에 [Packet] 어트리뷰트 적용 (partial 필수)
[Packet]
public partial class ModbusReadPacket
{
public byte FunctionCode { get; set; }
public ushort StartAddress { get; set; }
public ushort Quantity { get; set; }
}

// 2. 컴파일 후 자동 생성된 메서드 사용
var packet = new ModbusReadPacket
{
FunctionCode = 0x03,
StartAddress = 0x0000,
Quantity = 10
};

byte[] bytes = packet.ToBytesOptimized();

생성 코드 구조

// <auto-generated/>
// ModbusReadPacket_Packet.g.cs

using System;
using System.Buffers;

namespace YourNamespace
{
public partial class ModbusReadPacket
{
public byte[] ToBytesOptimized()
{
// 프로퍼티 기반 고성능 직렬화 코드
return new byte[10];
}
}
}

어트리뷰트 참조

[Packet]

Source Generator 처리 대상임을 표시합니다.

요구사항:

  • 클래스에 partial 키워드 필수
  • 어트리뷰트가 없으면 코드 생성 미적용
// ✅ 올바른 사용
[Packet]
public partial class MyPacket { }

// ❌ partial 없으면 동작 안 함 (컴파일 오류)
[Packet]
public class MyPacket { }

사용 예제

드라이버 패킷 정의

using Caffeine.Generators;

namespace Caffeine.Drivers.Modbus.Packets;

[Packet]
public partial class ModbusReadCoilsPacket
{
public byte DeviceId { get; set; }
public byte FunctionCode { get; set; } = 0x01;
public ushort StartAddress { get; set; }
public ushort CoilCount { get; set; }
}

[Packet]
public partial class ModbusWriteCoilPacket
{
public byte DeviceId { get; set; }
public byte FunctionCode { get; set; } = 0x05;
public ushort CoilAddress { get; set; }
public ushort Value { get; set; }
}

생성된 코드 활용

var readPacket = new ModbusReadCoilsPacket
{
DeviceId = 1,
StartAddress = 0x0100,
CoilCount = 8
};

// Source Generator가 생성한 메서드 호출
byte[] frame = readPacket.ToBytesOptimized();
await _tcpStream.WriteAsync(frame, cancellationToken);

xUnit 테스트

public class ModbusPacketTests
{
[Fact]
public void ToBytesOptimized_ShouldReturnNonEmptyArray()
{
var packet = new ModbusReadCoilsPacket
{
DeviceId = 1,
StartAddress = 0x0100,
CoilCount = 8
};

var bytes = packet.ToBytesOptimized();

Assert.NotNull(bytes);
Assert.True(bytes.Length > 0);
}
}

제한사항

제한설명
타겟 프레임워크netstandard2.0 (호스트 프로젝트와 무관)
partial 키워드[Packet] 클래스에 필수
IDE 재시작Generator 변경 후 IDE(Visual Studio/Rider) 재시작 필요할 수 있음
중첩 클래스중첩 클래스(nested class)에는 적용 불가
제네릭 클래스현재 버전에서 제네릭 타입 파라미터 미지원

IDE 설정

Visual Studio

Tools > Options > Text Editor > C# > Advanced:

  • "Show completion list in argument lists" 활성화
  • Roslyn Analyzer 경고 수준 조정

Visual Studio Code (C# Dev Kit)

Source Generator로 생성된 파일은 Analyzers 노드에서 확인 가능:

솔루션 탐색기
└── 참조
└── 분석기
└── Caffeine.Generators
└── ModbusReadCoilsPacket_Packet.g.cs

관련 문서