C# Source Generators Kavramı (C# 9+)
C# Source Generators kavramını öğrenin. Derleme zamanında kod üretimi ve performans avantajları örneklerle açıklanıyor.
C# 9 ile birlikte tanıtılan Source Generators, derleme zamanında (compile-time) ek C# kodu üreten güçlü bir Roslyn özelliğidir. Bu mekanizma, kodun çalışma anında değil, derleme sırasında yeni kod dosyaları oluşturur. Böylece runtime maliyeti olmadan tekrarlayan kodlar otomatik üretilir, performans artar ve bakım yükü azalır.
Source Generator Nedir?
Source Generator, derleyiciye eklenecek bir bileşendir. Derleyici (Roslyn), projenizdeki kaynak kodu analiz eder, ihtiyaç duyulan yerlere otomatik olarak yeni sınıflar veya metotlar ekler. Üretilen kod, derleme aşamasında proje içine dahil olur ve geliştirici tarafından normal C# kodu gibi kullanılabilir.
// Özet: Source Generator bir derleyici eklentisidir.
// Geliştirici özel mantık yazar, generator kod üretir.
// Derleme sonunda oluşturulan kod otomatik olarak projeye eklenir.
Ne Zaman Kullanılır?
- Tekrarlayan, manuel yazılması zor kodları otomatik üretmek için
- Performans kritik kodlarda reflection yerine compile-time çözüm üretmek için
- ORM, serializer, mapper, proxy, event, attribute tabanlı sistemlerde
- JSON veya API istemcileri gibi tip güvenli kod üretimi gereken durumlarda
Basit Bir Source Generator Örneği
Aşağıda en basit haliyle çalışan bir Source Generator örneği bulunmaktadır.
Bu generator, derleme sırasında yeni bir HelloGenerated sınıfı oluşturur.
// HelloGenerator.csproj (ayrı bir Class Library olmalı)
// Paket: Microsoft.CodeAnalysis.CSharp
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System.Text;
[Generator]
public class HelloGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
// Gerekirse analiz başında çalışır (örneğin syntax dinleme)
}
public void Execute(GeneratorExecutionContext context)
{
string code = @"
namespace HelloGen
{
public static class HelloGenerated
{
public static void SayHello() =>
System.Console.WriteLine(""Merhaba! Bu sınıf derleme sırasında üretildi."");
}
}";
context.AddSource("HelloGenerated.g.cs", SourceText.From(code, Encoding.UTF8));
}
}
// Ana projede kullanım
using HelloGen;
class Program
{
static void Main()
{
HelloGenerated.SayHello(); // Derleme sırasında üretilen kodu çağırır
}
}
Derleme sırasında bu kod dosyası otomatik oluşturulur. Visual Studio’da “Analyzers → HelloGenerator → HelloGenerated.g.cs” altında görülebilir.
Yapı: Generator Projesi Oluşturma
- Yeni bir Class Library (.NET Standard) projesi oluşturun.
- Proje dosyasına aşağıdaki özellikleri ekleyin:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<IncludeBuildOutput>false</IncludeBuildOutput>
<AnalyzerLanguage>C#</AnalyzerLanguage>
<OutputItemType>Analyzer</OutputItemType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
</ItemGroup>
</Project>
Bu yapı sayesinde proje bir “Analyzer/Generator” olarak kullanılabilir hale gelir. Daha sonra bu DLL’i ana projeye “Analyzer” olarak referans verin.
Attribute Bazlı Kod Üretimi
Gerçek dünyada generator’lar genellikle attribute’lar aracılığıyla tetiklenir.
Örneğin bir sınıfın üzerine [AutoToString] attribute’u eklediğinizde derleme sırasında otomatik bir ToString() metodu üretebilirsiniz.
// Kullanıcı kodu
[AutoToString]
public partial class Kisi
{
public string Ad { get; set; }
public int Yas { get; set; }
}
// Generator tarafından üretilen kod (derleme sırasında)
public partial class Kisi
{
public override string ToString() =>
$""Kisi: Ad={Ad}, Yas={Yas}"";
}
Bu yaklaşım, boilerplate (tekrarlayan) kodları ortadan kaldırarak bakım kolaylığı sağlar.
Incremental Source Generator (C# 10+)
C# 10 ile birlikte gelen Incremental Generator, performans ve incremental build desteği sunar. Yalnızca değişen dosyalar için kod yeniden üretilir.
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Text;
[Generator]
public class BasitIncrementalGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var sınıflar = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (syntaxNode, _) => syntaxNode is ClassDeclarationSyntax,
transform: (ctx, _) => (ClassDeclarationSyntax)ctx.Node)
.Collect();
context.RegisterSourceOutput(sınıflar, (spc, sınıfListesi) =>
{
foreach (var sınıf in sınıfListesi)
{
string ad = sınıf.Identifier.Text;
string kod = $@"
namespace AutoGen
{{
public static class {ad}Info
{{
public static void Yaz() =>
System.Console.WriteLine(""Sınıf: {ad}"");
}}
}}";
spc.AddSource($"{ad}Info.g.cs", SourceText.From(kod, Encoding.UTF8));
}
});
}
}
Bu modelle büyük projelerde derleme performansı ciddi oranda artar. Artık generator’lar yalnızca etkilenmiş dosyalar için çalışır.
Source Generator vs Reflection
| Özellik | Source Generator | Reflection |
|---|---|---|
| Çalışma Zamanı | Derleme Zamanı (Compile-time) | Çalışma Zamanı (Runtime) |
| Performans | Yüksek (kodu önceden üretir) | Düşük (çalışma anında analiz) |
| Kullanım Alanı | ORM, Serialization, API Client | Plugin, Test, Dinamik Tipler |
| Kod Görünürlüğü | Üretilen dosyalar proje içinde görülebilir | Yalnızca çalışma anında etkilidir |
Performans ve Dikkat Edilecekler
- Generator’lar read-only çalışır; mevcut dosyaları değiştiremez, yalnızca yeni kod ekler.
- Üretilen kodlar
.g.csuzantısıyla “Analyzers → Generated Files” altında görünür. - Ağır işlemler (ör. dosya erişimi, I/O) generator içinde yapılmamalıdır.
- Derleme süresini uzatmamak için gereksiz kod üretiminden kaçınılmalıdır.
- Kaynak kodu üreten metinler UTF-8 olarak oluşturulmalı ve
context.AddSource()ile eklenmelidir.
Örnek: Otomatik DTO Üretimi
Örneğin bir veritabanı tablosuna karşılık gelen modellerden DTO sınıfları üretmek istediğinizi düşünün.
Aşağıdaki Source Generator, her model için bir {ModelAdı}Dto sınıfı oluşturur.
// Model sınıfı
[AutoDto]
public class Kullanici
{
public int Id { get; set; }
public string Ad { get; set; }
}
// Üretilen kod
public class KullaniciDto
{
public int Id { get; set; }
public string Ad { get; set; }
}
Bu sayede manuel DTO yazma zahmeti ortadan kalkar, modeldeki değişiklikler otomatik yansır.
TL;DR
- Source Generators, derleme sırasında kod üreten Roslyn tabanlı araçlardır.
- Reflection gibi runtime maliyeti yoktur; performans ve güvenlik açısından daha verimlidir.
ISourceGeneratorveyaIIncrementalGeneratorarayüzleriyle uygulanır.- Oluşturulan kodlar proje derlemesine dahil edilir ve normal C# kodu gibi çalışır.
- Gerçek dünyada serializer, mapper, DTO generator veya API client üretimi için sıkça kullanılır.
İlişkili Makaleler
C# Generic Yapıları (List<T>, Dictionary<TKey,TValue>)
C# generic yapılarını öğrenin. List<T> ve Dictionary<TKey,TValue> ile tip güvenliği, yeniden kullanılabilirlik ve pratik örnekler.
C# ile SOLID Prensipleri
C# örnekleriyle SOLID prensiplerinin uygulanışı: daha esnek, sürdürülebilir ve test edilebilir kod tasarımları.
C# Reflection ve Late Binding
C#’ta Reflection ve Late Binding kullanımını öğrenin. Runtime tip keşfi, dinamik çağrılar ve esnek yapıların örnekleri anlatılıyor.
C# Roslyn Compiler API ile Kod Analizi
C#’ta Roslyn Compiler API ile kod analizi yapmayı öğrenin. Syntax tree, analiz ve code generation senaryoları örneklerle.
C# Span<T> ve Memory<T> ile Performans Optimizasyonu
C#’ta Span<T> ve Memory<T> ile performans optimizasyonunu öğrenin. Bellek yönetimi ve yüksek performanslı veri işlemleri örneklerle.