Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/AutoInject版本日志.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## v2026.05.22
- ⚡️新增`CustomModuleServiceConfigurationAttribute`,用于提供给`AutoInjectModuleGenerator`生成项目注入代码时,调用额外的服务注入
- ⚡️改进注入方法,现在可以使用`IHostApplicationBuilder`代替`IServiceCollection`作为参数, 如果子模式使用了`IHostApplicationBuilder`, 总入口必须使用`IHostApplicationBuilder`

## v2026.05.20
- ⚡️现在可以通过`AutoInjectAttribute`的`Factory`,`Instance`,`DeclaredType`等属性配置工厂模式或者实例的注入
Expand Down
123 changes: 58 additions & 65 deletions src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public static AutoInjectContextInfo CollectContextInfo(GeneratorAttributeSyntaxC
{
var classSymbol = (INamedTypeSymbol)context.TargetSymbol;
//context.TargetSymbol.GetAttribute(AutoInjectContext, out var contextAttr);
var ctxInfo = new AutoInjectContextInfo(classSymbol);
var ctxInfo = new AutoInjectContextInfo(classSymbol, context.TargetNode);
if (classSymbol.GetMembers().FirstOrDefault(m => m is IMethodSymbol
{
IsPartialDefinition: true, PartialImplementationPart: null, IsStatic: true
Expand All @@ -64,6 +64,7 @@ public static AutoInjectContextInfo CollectContextInfo(GeneratorAttributeSyntaxC
return ctxInfo;
}
ctxInfo.MethodSymbol = methodSymbol;
ctxInfo.IsHostBuilder = methodSymbol.Parameters.Any(p => p.Type.ToDisplayString().StartsWith("Microsoft.Extensions.Hosting"));
var allConfig = methodSymbol.GetAttributes(AutoInjectConfiguration).Select(c =>
{
var i = c.GetNamedValue("Include")?.ToString() ?? "";
Expand All @@ -86,37 +87,37 @@ public static AutoInjectContextInfo CollectContextInfo(GeneratorAttributeSyntaxC
return ctxInfo;
}

public static AutoInjectContextInfo CollectContextInfo(GeneratorSyntaxCollectInfoContext context)
{
var classSymbol = (INamedTypeSymbol)context.TargetSymbol;
var ctxInfo = new AutoInjectContextInfo(classSymbol);
if (classSymbol.GetMembers().FirstOrDefault(m => m is IMethodSymbol
{
IsPartialDefinition: true, PartialImplementationPart: null, IsStatic: true
}) is not IMethodSymbol methodSymbol)
{
ctxInfo.Diagnostic = DiagnosticDefinitions.AIG00001(context.GetDiagnosticLocation());
return ctxInfo;
}
ctxInfo.MethodSymbol = methodSymbol;
var allConfig = methodSymbol.GetAttributes(AutoInjectConfiguration).Select(c =>
{
var i = c.GetNamedValue("Include")?.ToString() ?? "";
var e = c.GetNamedValue("Exclude")?.ToString() ?? "";
return (i, e);
}).ToArray();
//public static AutoInjectContextInfo CollectContextInfo(GeneratorSyntaxCollectInfoContext context)
//{
// var classSymbol = (INamedTypeSymbol)context.TargetSymbol;
// var ctxInfo = new AutoInjectContextInfo(classSymbol);
// if (classSymbol.GetMembers().FirstOrDefault(m => m is IMethodSymbol
// {
// IsPartialDefinition: true, PartialImplementationPart: null, IsStatic: true
// }) is not IMethodSymbol methodSymbol)
// {
// ctxInfo.Diagnostic = DiagnosticDefinitions.AIG00001(context.GetDiagnosticLocation());
// return ctxInfo;
// }
// ctxInfo.MethodSymbol = methodSymbol;
// var allConfig = methodSymbol.GetAttributes(AutoInjectConfiguration).Select(c =>
// {
// var i = c.GetNamedValue("Include")?.ToString() ?? "";
// var e = c.GetNamedValue("Exclude")?.ToString() ?? "";
// return (i, e);
// }).ToArray();

ctxInfo.Includes = [.. allConfig.Select(t => t.i).Where(s => !string.IsNullOrEmpty(s))];
// ctxInfo.Includes = [.. allConfig.Select(t => t.i).Where(s => !string.IsNullOrEmpty(s))];

ctxInfo.Excludes = [.. allConfig.Select(t => t.e).Where(s => !string.IsNullOrEmpty(s))];
if (ctxInfo.Includes.Intersect(ctxInfo.Excludes).Any())
{
var methodLocation = methodSymbol.TryGetLocation();
ctxInfo.Diagnostic = DiagnosticDefinitions.AIG00002(methodLocation);
return ctxInfo;
}
return ctxInfo;
}
// ctxInfo.Excludes = [.. allConfig.Select(t => t.e).Where(s => !string.IsNullOrEmpty(s))];
// if (ctxInfo.Includes.Intersect(ctxInfo.Excludes).Any())
// {
// var methodLocation = methodSymbol.TryGetLocation();
// ctxInfo.Diagnostic = DiagnosticDefinitions.AIG00002(methodLocation);
// return ctxInfo;
// }
// return ctxInfo;
//}

//public static AutoInjectInfo CollectInjectInfo(GeneratorSyntaxCollectInfoContext context)
//{
Expand Down Expand Up @@ -340,55 +341,47 @@ AutoInjectInfo BuildFormManualInjectConfig(AttributeData a)
}
}

public static AutoInjectInfo CollectCustomInject(INamedTypeSymbol classSymbol, SyntaxNode targetNode)
public static AutoInjectInfo CollectCustomInject(IMethodSymbol methodSymbol, SyntaxNode targetNode)
{
var classSymbol = methodSymbol.ContainingType;
var info = new AutoInjectInfo(classSymbol)
{
CustomInject = true,
};
var methods = classSymbol.GetMethods(m => m.IsStatic);
IMethodSymbol? best = null;
foreach (var method in methods)
if (methodSymbol.Parameters.Length > 2)
{
if (method.Parameters.Length > 2)
{
info.Diagnostic = DiagnosticDefinitions.AIG00008(targetNode.GetLocation());
return info;
}
if (!CheckFirstParameter(method))
{
info.Diagnostic = DiagnosticDefinitions.AIG00009(targetNode.GetLocation());
return info;
}
best ??= method;
var p2check = CheckSecondParameter(method);
if (p2check.HasValue)
{
if (p2check.Value)
{
best = method;
break;
}
else
{
info.Diagnostic = DiagnosticDefinitions.AIG00010(targetNode.GetLocation());
return info;
}
}
info.Diagnostic = DiagnosticDefinitions.AIG00008(targetNode.GetLocation());
return info;
}
if (best is null)
if (!CheckFirstParameter(methodSymbol, out bool isHostBuilder))
{
info.Diagnostic = DiagnosticDefinitions.AIG00011(targetNode.GetLocation());
info.Diagnostic = DiagnosticDefinitions.AIG00009(targetNode.GetLocation());
return info;
}
info.CustomInjectInfo = new CustomInjectInfo(best.Parameters.Length, best.Name);
var p2check = CheckSecondParameter(methodSymbol);
if (p2check.HasValue)
{
if (!p2check.Value)
{
info.Diagnostic = DiagnosticDefinitions.AIG00010(targetNode.GetLocation());
return info;
}
}
info.CustomInjectInfo = new CustomInjectInfo(methodSymbol.Parameters.Length, methodSymbol.Name, isHostBuilder);
return info;

static bool CheckFirstParameter(IMethodSymbol method)
static bool CheckFirstParameter(IMethodSymbol method, out bool isHostBuilder)
{
if (method.Parameters.Length > 0 && method.Parameters[0].Type.ToDisplayString() == "Microsoft.Extensions.DependencyInjection.IServiceCollection")
isHostBuilder = false;
if (method.Parameters.Length > 0)
{
return true;
if (method.Parameters[0].Type.ToDisplayString() == "Microsoft.Extensions.DependencyInjection.IServiceCollection")
return true;
if (method.Parameters[0].Type.ToDisplayString().StartsWith("Microsoft.Extensions.Hosting")) // Microsoft.Extensions.Hosting.IHostApplicationBuilder
{
isHostBuilder = true;
return true;
}
}
return false;
}
Expand Down
5 changes: 4 additions & 1 deletion src/AutoInject.Roslyn/AutoInjectContextInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

namespace AutoInjectGenerator;

public class AutoInjectContextInfo(INamedTypeSymbol targetSymbol)
public class AutoInjectContextInfo(INamedTypeSymbol targetSymbol, SyntaxNode node)
{
public INamedTypeSymbol TargetSymbol { get; } = targetSymbol;
public SyntaxNode Node { get; } = node;

public string ClassName => TargetSymbol.MetadataName;
public IMethodSymbol? MethodSymbol { get; set; }
public bool IsHostBuilder { get; set; }
public string[] Includes { get; set; } = [];
public string[] Excludes { get; set; } = [];
public bool? ContainSelf { get; set; }
Expand Down
69 changes: 60 additions & 9 deletions src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using static AutoInjectGenerator.AutoInjectContextGeneratorHelpers;
Expand All @@ -20,7 +21,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
var target = source.TargetSymbol;
var asm = target.ContainingAssembly;
var modules = new List<INamedTypeSymbol>();
var modules = new List<(INamedTypeSymbol, bool)>();
source.ContainSelf = asm.GlobalNamespace?.GetAllMembers<INamedTypeSymbol>(i => i is INamedTypeSymbol m && m.HasAttribute(AutoInject, true)).Any();

foreach (var item in asm.Modules)
Expand All @@ -31,7 +32,26 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
continue;

if (referencedAssembly.GlobalNamespace is null) continue;
modules.AddRange(referencedAssembly.GlobalNamespace.GetAllMembers<INamedTypeSymbol>(i => i is INamedTypeSymbol m && m.HasAttribute(AutoInjectModule)));

var moduleInit = referencedAssembly.GlobalNamespace.GetAllMembers<INamedTypeSymbol>(i => i is INamedTypeSymbol m && m.HasAttribute(AutoInjectModule)).FirstOrDefault();
if (moduleInit is null)
continue;
var customInject = referencedAssembly.GlobalNamespace.GetAllMembers<IMethodSymbol>(i => i is IMethodSymbol m && m.HasAttribute(CustomInject));
bool isHostBuilder = false;
foreach (var cc in customInject)
{
if (cc.Parameters.Any(p => p.Type.ToDisplayString().StartsWith("Microsoft.Extensions.Hosting")))
{
isHostBuilder = true;
if (!source.IsHostBuilder)
{
spc.ReportDiagnostic(DiagnosticDefinitions.AIG00012(source.Node.GetLocation()));
return;
}
break;
}
}
modules.Add((moduleInit, isHostBuilder));
}
}
var file = CreateCodeFile(source, modules);
Expand All @@ -42,7 +62,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
});
}

private static CodeFile? CreateCodeFile(AutoInjectContextInfo context, List<INamedTypeSymbol> modules)
private static CodeFile? CreateCodeFile(AutoInjectContextInfo context, List<(INamedTypeSymbol, bool)> modules)
{
var classSymbol = context.TargetSymbol;
var className = context.ClassName;
Expand All @@ -53,8 +73,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.AddGeneratedCodeAttribute(typeof(AutoInjectContextGenerator))
.Modifiers("static partial");

var serviceName = methodSymbol.Parameters.First(p =>
p.Type.ToDisplayString().Contains("Microsoft.Extensions.DependencyInjection.IServiceCollection")).Name;
var serviceName = methodSymbol.Parameters.FirstOrDefault(p =>
p.Type.ToDisplayString().Contains("Microsoft.Extensions.DependencyInjection.IServiceCollection"))?.Name;

if (serviceName is null)
{
serviceName = methodSymbol.Parameters.FirstOrDefault(p => p.Type.ToDisplayString().StartsWith("Microsoft.Extensions.Hosting"))?.Name;
context.IsHostBuilder = true;
}

var includeField = FieldBuilder.Default
.Modifiers("private static readonly")
Expand All @@ -68,22 +94,46 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.InitializeWith($"[{string.Join(", ", context.Excludes.Select(s => $"\"{s}\""))}] ");

var cm = MethodBuilder.Default.Partial(methodSymbol);
{
// 创建配置

{// 创建配置
List<string> methodBody = [
"var config = new global::AutoInjectGenerator.AutoInjectConfiguration(_excludes, _includes)",
//$"global::AutoInjectGenerator.AutoInjectManager.ApplyProjectServices({serviceName}, config)"
];
if (context.ContainSelf == true)
{
methodBody.Add($"global::{context.TargetSymbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)");
if (context.IsHostBuilder)
{
methodBody.Add($"global::{context.TargetSymbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}.Services, config)");
}
else
{
methodBody.Add($"global::{context.TargetSymbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)");
}
}
foreach (var item in modules)
{
methodBody.Add($"global::{item.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)");
var symbol = item.Item1;
var isHostBuilder = item.Item2;
if (isHostBuilder)
{
methodBody.Add($"global::{symbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)");
}
else
{
if (context.IsHostBuilder)
{
methodBody.Add($"global::{symbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}.Services, config)");
}
else
{
methodBody.Add($"global::{symbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)");
}
}
}
cm.AddBody([.. methodBody]);
}

gclass.AddMembers(includeField);
gclass.AddMembers(excludeField);
gclass.AddMembers(cm);
Expand All @@ -100,3 +150,4 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return file;
}
}

2 changes: 1 addition & 1 deletion src/AutoInject.Roslyn/AutoInjectInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class AutoInjectInfo(INamedTypeSymbol targetSymbol)
//public string? MemberShip { get; set; }
}

public record CustomInjectInfo(int ParameterCount, string MethodName);
public record CustomInjectInfo(int ParameterCount, string MethodName, bool IsHostBuilder);

public record RegisterServiceInfo(string Scoped, string ServiceType, string? Key, string? MemberShip, string? Factory, string? Instance, INamedTypeSymbol DeclaredType)
{
Expand Down
Loading
Loading