02. source generator

1️⃣ Source Generator 개요
📚 Microsoft Docs: Microsoft Learn / Learn / .NET / MVVM

✅ 소스 생성기(SG, Source Generator)란?
소스 생성기는 .NET 5부터 도입된 기능으로, 우리가 반복적으로 작성하던 MVVM 관련 C# 코드를 컴파일 타임에 자동으로 생성하여 프로젝트에 생성해주는 컴파일러 확장 도구 입니다.
✅ 사용 방법
개발자가 클래스에 partial 키워드와 특정 어트리뷰트[attribute]를 붙이면,
프로젝트가 빌드될 때 필요한 코드를 자동으로 생성합니다.
2️⃣ 단순 소스코드 비교 (기본 C# MVVM 구현 VS Source Generator )
*단순히 소스코드의 양 자체만 비교해봅니다.
✔️ 1. 순수 C#으로 INotifyPropertyChanged와 ICommand를 직접 구현
// 기본 C#으로 INotifyPropertyChanged 상속받아 MVVM 구현 public class MainViewModel : INotifyPropertyChanged { private string userName; public string UserName { get => userName; set { if (userName != value) { userName = value; OnPropertyChanged(); // nameof(UserName) 자동 전달 } } } public ICommand SayHelloCommand { get; } public MainViewModel() { SayHelloCommand = new RelayCommand(SayHello); } private void SayHello() { Console.WriteLine($"안녕하세요, {UserName}님!"); } public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
// 간단한 ICommand 구현 public class RelayCommand : ICommand { private readonly Action execute; private readonly Func<bool>? canExecute; public RelayCommand(Action execute, Func<bool>? canExecute = null) { this.execute = execute; this.canExecute = canExecute; } public event EventHandler? CanExecuteChanged; public bool CanExecute(object? parameter) => canExecute?.Invoke() ?? true; public void Execute(object? parameter) => execute(); public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); }
✔️ 2. SG(Source Generator) 사용
public partial class MainViewModel : ObservableObject { [ObservableProperty] private string userName; [RelayCommand] private void SayHello() { Console.WriteLine($"Hello, {UserName}"); } }
*수동으로 구현하면 수십 줄인데, source generator를 쓰면 1~2줄로 해결됩니다.
3️⃣ Source Generator 자동완성 구조 살펴보기 - (1) ObservableProperty
*CommunityToolkit.Mvvm 패키지 설치 후 진행해주세요.
✔️ 1. ObservableProperty 사용해보기

① 프로젝트를 생성하고, 폴더 하나를 만든 뒤, 테스트용 클래스 파일을만들어 줍니다.

② 필드(userName) 하나를 생성하고, ③ [ObservableProperty] 어트리뷰트를 추가하면,
④ 관련 패키지의 네임스페이스가 자동 추가됩니다.

⑤ ViewModel 클래스에 ObservableObject 를 상속받고, ⑥ 클래스는 partial 로 변경한 뒤, ⑦ 빌드합니다.
✔️ 2. Source Generator가 자동 생성한 구현부 살펴보기

① CommunityToolkit.Mvvm 패키지의 Source Generator는 ② MVVM에 필요한 소스코드를 자동 완성해줍니다.
② 솔루션 탐색기에서, 자동완성된 On___Changed 함수를 더블 클릭합니다.

③ 테스트용 ViewModel 클래스 파일의 partial 클래스에, ④ 자동완성된 MVVM 코드들을 확인 할 수 있습니다.
4️⃣ Source Generator 자동완성 구조 살펴보기 - (2) RelayCommand
✔️ 1. RelayCommand 사용해보기

① 프로젝트를 생성하고, 폴더 하나를 만든 뒤, 테스트용 클래스 파일을만들어 줍니다.

② 메서드 SayHello( )를 생성하고, ③ [RelayCommand] 어트리뷰트를 추가하면,
④ 관련 패키지의 네임스페이스가 자동 추가됩니다.

⑤ ObservableObject 를 상속받고, ⑥ 클래스는 partial 로 변경한 뒤, ⑦ 빌드합니다.
✔️ 2. Source Generator가 자동 생성한 구현부 살펴보기

① CommunityToolkit.Mvvm 패키지의 Source Generator는 ② MVVM에 필요한 소스코드를 자동 완성해줍니다.
② 솔루션 탐색기에서, 자동완성된 ___Command 함수를 더블 클릭합니다.

③ 테스트용 클래스 파일의 partial 클래스에, ④자동완성된 코드를 확인 할 수 있습니다.
5️⃣ Attribute [어트리뷰트]
*Attribute를 '특성'이라는 한국어로 사용하면, 혼동될 상황이 많다.
✔️ 사용 문법
[AttributeName]
[AttributeName(parameter1, parameter2, ...)]
※ [RelayCommand]는 실제로 RelayCommandAttribute 입니다. Attribute로 끝나지만, 사용할 땐 생략 가능합니다.
✔️ 예제 기반 사용법 설명
[ObservableProperty] private string userName;
- 이 필드는 자동으로 public string UserName 프로퍼티로 구현되고
- PropertyChanged 이벤트도 함께 발생시키는 코드가 컴파일 시 자동 생성됩니다.
[RelayCommand] private void ShowGreeting()
- ShowGreetingCommand라는 ICommand 속성을 자동으로 만들어서 XAML에서 사용할 수 있게 해줍니다.
✔️ 핵심 요약
[ ] 안에 사용된 것은 Attribute(특성)이며,
컴파일러나 도구에게 특별한 의미나 동작을 지정하는 메타데이터입니다.
CommunityToolkit.Mvvm 패키지는 어트리뷰트를 활용해 MVVM 코드를 간결하게 자동 생성하게 도와줍니다.
6️⃣ partial 키워드를 사용하는 이유
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using System.Windows; namespace WpfApp.ViewModels { // partial 키워드를 사용하는 이유: // Source Generator가 자동으로 생성하는 코드(예: UserName 속성, ShowGreetingCommand 명령)를 // 동일 클래스 이름의 다른 partial 파일로 분리하여 추가할 수 있게 해줌 // 즉, 수동 작성 코드와 자동 생성 코드를 분리하여 관리 가능하게 함 namespace WPF_ToolKit01.ViewModel { internal partial class MainViewModel : ObservableObject { [ObservableProperty] private string? userName; [RelayCommand] private void ShowGreeting() { MessageBox.Show($"Hello, {UserName}!"); } } }


7️⃣ 예제
✔️ 1. 동작 시나리오

- 텍스트 박스에 이름 입력
- 버튼 클릭
- 메시지 박스에 "Hello, {입력한 이름}!" 출력
✔️ 2. CommunityToolkit.Mvvm 으로 구현
📁 2.1 프로젝트 구조
02_WpfMvvmToolkit_Eg01/ ├── ViewModels/ │ ├── MainViewModel.cs └── Views/ ├── MainWindow.xaml ← 메인 뷰 └── MainWindow.xaml.cs
📁 2.2 ViewModel 클래스 만들기

using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using System.Windows;
internal partial class MainViewModel : ObservableObject { [ObservableProperty] private string? userName; [RelayCommand] private void ShowGreeting() { MessageBox.Show($"Hello, {UserName}!"); } }
📁 2.3 XAML 화면 구성

xmlns:vm="clr-namespace:WPF_ToolKit01.ViewModel" Title="Toolkit.MVVM Example" Height="200" Width="300"> <Window.DataContext> <vm:MainViewModel /> </Window.DataContext> <StackPanel Margin="20"> <TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" /> <Button Content="Greet" Command="{Binding ShowGreetingCommand}" Margin="0,10,0,0"/> </StackPanel>
✔️ 3. 소스코드
8️⃣ 예제 - 상세 주석
✔️ ViewModel 클래스 상세 주석
using CommunityToolkit.Mvvm.ComponentModel; // MVVM에서 속성 변경 알림(INotifyPropertyChanged)을 지원하는 기본 클래스 제공 using CommunityToolkit.Mvvm.Input; // ICommand 구현을 쉽게 하기 위한 특성(Attribute) 지원 using System.Windows; // WPF의 기본 UI 요소(MessageBox 등) 사용을 위해 필요
// ViewModel 클래스는 ObservableObject를 상속하여 속성 변경 알림 기능을 자동으로 제공 // partial 키워드를 사용하는 이유: // - Source Generator가 자동으로 생성하는 코드(예: UserName 속성, ShowGreetingCommand 명령)를 // - 동일 클래스 이름의 다른 partial 파일로 분리하여 추가할 수 있게 해줌 // - 즉, 수동 작성 코드와 자동 생성 코드를 분리하여 관리 가능하게 함 public partial class MainViewModel : ObservableObject { // [ObservableProperty]는 다음과 같은 코드를 자동 생성해줌: // public string UserName // { // get => userName; // set => SetProperty(ref userName, value); // } // 또한, 속성 변경 시 INotifyPropertyChanged 이벤트를 발생시킴 [ObservableProperty] private string userName; // 사용자 이름을 저장할 속성 (자동으로 UserName 속성 생성됨) // [RelayCommand]는 다음과 같은 코드를 자동 생성해줌: // public ICommand ShowGreetingCommand => new RelayCommand(ShowGreeting); // 즉, 이 메서드를 바탕으로 ICommand를 구현한 명령 속성이 자동 생성됨 // 이 명령은 XAML에서 버튼 클릭과 같은 이벤트에 바인딩할 수 있음 [RelayCommand] private void ShowGreeting() { // 사용자 이름을 포함한 환영 메시지를 MessageBox로 표시 MessageBox.Show($"Hello, {UserName}!"); } }
✅ 어트리뷰트와 자동 구현된 기능:
- [ObservableProperty]: INotifyPropertyChanged 자동 생성
- [RelayCommand]: ICommand 구현부 자동 생성
✅ 자동 생성되는 것:
- UserName 속성 + OnPropertyChanged 호출
- ShowGreetingCommand 명령 생성 (사용자 정의한 ShowGreeting에 의해)
✅ 요약
기능 | 설명 |
[ObservableProperty] | 필드 → 속성 자동 생성 + 변경 알림 |
[RelayCommand] | 메서드 → ICommand 구현 자동 생성 |
ViewModel은 ObservableObject를 상속 | MVVM 패턴의 핵심 기능을 제공 |
✔️ XAML 화면 구성
<!-- 태그(< >꺽쇠기호 내부)안에는 아래 주석 추가가 불가능합니다. --> <!-- WPF 기본 UI 요소를 위한 XML 네임스페이스 --> xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <!-- 디자인 타임 지원 (Blend 등에서 사용) --> xmlns:d="http://schemas.microsoft.com/expression/blend/2008" <!-- 현재 프로젝트의 기본 네임스페이스 --> xmlns:local="clr-namespace:WpfApp" <!-- ViewModel 클래스가 위치한 네임스페이스 --> xmlns:vm="clr-namespace:WpfApp.ViewModels" <!-- 윈도우 제목 및 크기 설정 --> Title="Toolkit.MVVM Example" Height="200" Width="300">
<Window.DataContext> <vm:MainViewModel /> <!-- ViewModel 인스턴스를 XAML의 DataContext로 설정 --> </Window.DataContext> <StackPanel Margin="20"> <!-- 수직 방향으로 자식 요소를 배치하는 레이아웃 컨트롤 --> <!-- TextBox는 ViewModel의 UserName 속성과 양방향 바인딩됨 --> <!-- UpdateSourceTrigger=PropertyChanged : 텍스트가 바뀔 때마다 즉시 ViewModel로 전달 --> <TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" /> <!-- Button 클릭 시 ViewModel의 ShowGreetingCommand 명령을 실행 --> <!-- Margin="0,10,0,0"은 위쪽 여백을 줘서 간격 확보 --> <Button Content="인사" Command="{Binding ShowGreetingCommand}" Margin="0,10,0,0"/> </StackPanel> </Window>
댓글을 사용할 수 없습니다.