using Apq.Cfg.DependencyInjection;
using BenchmarkDotNet.Attributes;
namespace Apq.Cfg.Benchmarks;
///
/// 源生成器绑定性能测试
/// 对比源生成器(零反射)与 ObjectBinder(反射)的性能差异
///
[MemoryDiagnoser]
[RankColumn]
public class SourceGeneratorBenchmarks
{
private string _testDir = null!;
private ICfgRoot _cfg = null!;
private ICfgSection _simpleSection = null!;
private ICfgSection _nestedSection = null!;
private ICfgSection _arraySection = null!;
private ICfgSection _dictionarySection = null!;
private ICfgSection _complexSection = null!;
[GlobalSetup]
public void Setup()
{
_testDir = Path.Combine(Path.GetTempPath(), $"ApqCfgSgBench_{Guid.NewGuid():N}");
Directory.CreateDirectory(_testDir);
var jsonPath = Path.Combine(_testDir, "config.json");
File.WriteAllText(jsonPath, """
{
"Simple": {
"Name": "TestApp",
"Port": 8080,
"Enabled": true,
"Timeout": 30.5,
"Id": "550e8400-e29b-41d4-a716-446655440000"
},
"Nested": {
"Name": "ParentApp",
"Database": {
"Host": "localhost",
"Port": 5432,
"Name": "testdb"
},
"Cache": {
"Host": "redis.local",
"Port": 6379
}
},
"Array": {
"Tags": {
"0": "tag1",
"1": "tag2",
"2": "tag3",
"3": "tag4",
"4": "tag5"
},
"Ports": {
"0": 80,
"1": 443,
"2": 8080,
"3": 8443
}
},
"Dictionary": {
"Settings": {
"Key1": "Value1",
"Key2": "Value2",
"Key3": "Value3",
"Key4": "Value4",
"Key5": "Value5"
}
},
"Complex": {
"Name": "ComplexApp",
"Endpoints": {
"0": {
"Host": "api1.local",
"Port": 8001
},
"1": {
"Host": "api2.local",
"Port": 8002
},
"2": {
"Host": "api3.local",
"Port": 8003
}
},
"Metadata": {
"version": "1.0.0",
"author": "test",
"description": "A complex configuration"
}
}
}
""");
_cfg = new CfgBuilder()
.AddJson(jsonPath, level: 0, writeable: false)
.Build();
_simpleSection = _cfg.GetSection("Simple");
_nestedSection = _cfg.GetSection("Nested");
_arraySection = _cfg.GetSection("Array");
_dictionarySection = _cfg.GetSection("Dictionary");
_complexSection = _cfg.GetSection("Complex");
}
[GlobalCleanup]
public void Cleanup()
{
(_cfg as IDisposable)?.Dispose();
if (Directory.Exists(_testDir))
{
try { Directory.Delete(_testDir, true); }
catch { }
}
}
// ========== 简单类型绑定对比 ==========
[Benchmark(Description = "SourceGen_SimpleTypes")]
[BenchmarkCategory("Simple")]
public SgSimpleOptions SourceGen_SimpleTypes()
{
return SgSimpleOptions.BindFrom(_simpleSection);
}
[Benchmark(Description = "Reflection_SimpleTypes")]
[BenchmarkCategory("Simple")]
public ReflectionSimpleOptions Reflection_SimpleTypes()
{
var options = new ReflectionSimpleOptions();
ObjectBinder.BindSection(_simpleSection, options);
return options;
}
[Benchmark(Description = "SourceGen_SimpleTypes_100")]
[BenchmarkCategory("Simple")]
public SgSimpleOptions SourceGen_SimpleTypes_100()
{
SgSimpleOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = SgSimpleOptions.BindFrom(_simpleSection);
}
return options;
}
[Benchmark(Description = "Reflection_SimpleTypes_100")]
[BenchmarkCategory("Simple")]
public ReflectionSimpleOptions Reflection_SimpleTypes_100()
{
ReflectionSimpleOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = new ReflectionSimpleOptions();
ObjectBinder.BindSection(_simpleSection, options);
}
return options;
}
// ========== 嵌套对象绑定对比 ==========
[Benchmark(Description = "SourceGen_NestedObject")]
[BenchmarkCategory("Nested")]
public SgNestedOptions SourceGen_NestedObject()
{
return SgNestedOptions.BindFrom(_nestedSection);
}
[Benchmark(Description = "Reflection_NestedObject")]
[BenchmarkCategory("Nested")]
public ReflectionNestedOptions Reflection_NestedObject()
{
var options = new ReflectionNestedOptions();
ObjectBinder.BindSection(_nestedSection, options);
return options;
}
[Benchmark(Description = "SourceGen_NestedObject_100")]
[BenchmarkCategory("Nested")]
public SgNestedOptions SourceGen_NestedObject_100()
{
SgNestedOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = SgNestedOptions.BindFrom(_nestedSection);
}
return options;
}
[Benchmark(Description = "Reflection_NestedObject_100")]
[BenchmarkCategory("Nested")]
public ReflectionNestedOptions Reflection_NestedObject_100()
{
ReflectionNestedOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = new ReflectionNestedOptions();
ObjectBinder.BindSection(_nestedSection, options);
}
return options;
}
// ========== 数组/列表绑定对比 ==========
[Benchmark(Description = "SourceGen_Array")]
[BenchmarkCategory("Array")]
public SgArrayOptions SourceGen_Array()
{
return SgArrayOptions.BindFrom(_arraySection);
}
[Benchmark(Description = "Reflection_Array")]
[BenchmarkCategory("Array")]
public ReflectionArrayOptions Reflection_Array()
{
var options = new ReflectionArrayOptions();
ObjectBinder.BindSection(_arraySection, options);
return options;
}
[Benchmark(Description = "SourceGen_Array_100")]
[BenchmarkCategory("Array")]
public SgArrayOptions SourceGen_Array_100()
{
SgArrayOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = SgArrayOptions.BindFrom(_arraySection);
}
return options;
}
[Benchmark(Description = "Reflection_Array_100")]
[BenchmarkCategory("Array")]
public ReflectionArrayOptions Reflection_Array_100()
{
ReflectionArrayOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = new ReflectionArrayOptions();
ObjectBinder.BindSection(_arraySection, options);
}
return options;
}
// ========== 字典绑定对比 ==========
[Benchmark(Description = "SourceGen_Dictionary")]
[BenchmarkCategory("Dictionary")]
public SgDictionaryOptions SourceGen_Dictionary()
{
return SgDictionaryOptions.BindFrom(_dictionarySection);
}
[Benchmark(Description = "Reflection_Dictionary")]
[BenchmarkCategory("Dictionary")]
public ReflectionDictionaryOptions Reflection_Dictionary()
{
var options = new ReflectionDictionaryOptions();
ObjectBinder.BindSection(_dictionarySection, options);
return options;
}
[Benchmark(Description = "SourceGen_Dictionary_100")]
[BenchmarkCategory("Dictionary")]
public SgDictionaryOptions SourceGen_Dictionary_100()
{
SgDictionaryOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = SgDictionaryOptions.BindFrom(_dictionarySection);
}
return options;
}
[Benchmark(Description = "Reflection_Dictionary_100")]
[BenchmarkCategory("Dictionary")]
public ReflectionDictionaryOptions Reflection_Dictionary_100()
{
ReflectionDictionaryOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = new ReflectionDictionaryOptions();
ObjectBinder.BindSection(_dictionarySection, options);
}
return options;
}
// ========== 复杂对象绑定对比 ==========
[Benchmark(Description = "SourceGen_ComplexObject")]
[BenchmarkCategory("Complex")]
public SgComplexOptions SourceGen_ComplexObject()
{
return SgComplexOptions.BindFrom(_complexSection);
}
[Benchmark(Description = "Reflection_ComplexObject")]
[BenchmarkCategory("Complex")]
public ReflectionComplexOptions Reflection_ComplexObject()
{
var options = new ReflectionComplexOptions();
ObjectBinder.BindSection(_complexSection, options);
return options;
}
[Benchmark(Description = "SourceGen_ComplexObject_100")]
[BenchmarkCategory("Complex")]
public SgComplexOptions SourceGen_ComplexObject_100()
{
SgComplexOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = SgComplexOptions.BindFrom(_complexSection);
}
return options;
}
[Benchmark(Description = "Reflection_ComplexObject_100")]
[BenchmarkCategory("Complex")]
public ReflectionComplexOptions Reflection_ComplexObject_100()
{
ReflectionComplexOptions options = null!;
for (int i = 0; i < 100; i++)
{
options = new ReflectionComplexOptions();
ObjectBinder.BindSection(_complexSection, options);
}
return options;
}
// ========== BindTo 对比 ==========
[Benchmark(Description = "SourceGen_BindTo")]
[BenchmarkCategory("BindTo")]
public SgSimpleOptions SourceGen_BindTo()
{
var options = new SgSimpleOptions();
SgSimpleOptions.BindTo(_simpleSection, options);
return options;
}
[Benchmark(Description = "Reflection_BindTo")]
[BenchmarkCategory("BindTo")]
public ReflectionSimpleOptions Reflection_BindTo()
{
var options = new ReflectionSimpleOptions();
ObjectBinder.BindSection(_simpleSection, options);
return options;
}
}
// ========== 源生成器配置类(使用 [CfgSection] 特性) ==========
[CfgSection]
public partial class SgSimpleOptions
{
public string? Name { get; set; }
public int Port { get; set; }
public bool Enabled { get; set; }
public double Timeout { get; set; }
public Guid Id { get; set; }
}
[CfgSection]
public partial class SgNestedOptions
{
public string? Name { get; set; }
public SgDatabaseOptions? Database { get; set; }
public SgCacheOptions? Cache { get; set; }
}
[CfgSection]
public partial class SgDatabaseOptions
{
public string? Host { get; set; }
public int Port { get; set; }
public string? Name { get; set; }
}
[CfgSection]
public partial class SgCacheOptions
{
public string? Host { get; set; }
public int Port { get; set; }
}
[CfgSection]
public partial class SgArrayOptions
{
public string[]? Tags { get; set; }
public List? Ports { get; set; }
}
[CfgSection]
public partial class SgDictionaryOptions
{
public Dictionary? Settings { get; set; }
}
[CfgSection]
public partial class SgComplexOptions
{
public string? Name { get; set; }
public List? Endpoints { get; set; }
public Dictionary? Metadata { get; set; }
}
[CfgSection]
public partial class SgEndpointOptions
{
public string? Host { get; set; }
public int Port { get; set; }
}
// ========== 反射绑定配置类(用于对比) ==========
public class ReflectionSimpleOptions
{
public string? Name { get; set; }
public int Port { get; set; }
public bool Enabled { get; set; }
public double Timeout { get; set; }
public Guid Id { get; set; }
}
public class ReflectionNestedOptions
{
public string? Name { get; set; }
public ReflectionDatabaseOptions? Database { get; set; }
public ReflectionCacheOptions? Cache { get; set; }
}
public class ReflectionDatabaseOptions
{
public string? Host { get; set; }
public int Port { get; set; }
public string? Name { get; set; }
}
public class ReflectionCacheOptions
{
public string? Host { get; set; }
public int Port { get; set; }
}
public class ReflectionArrayOptions
{
public string[]? Tags { get; set; }
public List? Ports { get; set; }
}
public class ReflectionDictionaryOptions
{
public Dictionary? Settings { get; set; }
}
public class ReflectionComplexOptions
{
public string? Name { get; set; }
public List? Endpoints { get; set; }
public Dictionary? Metadata { get; set; }
}
public class ReflectionEndpointOptions
{
public string? Host { get; set; }
public int Port { get; set; }
}