-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
442 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System; | ||
namespace Biwen.AutoClassGen.Attributes | ||
{ | ||
|
||
/// <summary> | ||
/// Auto Decoration Attribute | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = true, Inherited = false)] | ||
public class AutoDecorAttribute : Attribute | ||
{ | ||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:删除未使用的参数", Justification = "<挂起>")] | ||
public AutoDecorAttribute(Type implement) { } | ||
} | ||
|
||
#if NET7_0_OR_GREATER | ||
|
||
/// <summary> | ||
/// Auto Decoration Attribute | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = true, Inherited = false)] | ||
#pragma warning disable SA1402 // File may only contain a single type | ||
public class AutoDecorAttribute<T> : AutoDecorAttribute where T : class | ||
#pragma warning restore SA1402 // File may only contain a single type | ||
{ | ||
public AutoDecorAttribute() : base(typeof(T)) | ||
{ | ||
} | ||
} | ||
|
||
#endif | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,17 @@ public class SourceGenerator : IIncrementalGenerator | |
private const string AttributeMetadataNameDtoG = "Biwen.AutoClassGen.Attributes.AutoDtoAttribute`1"; | ||
|
||
|
||
private const string AttributeMetadataNameDecor = "Biwen.AutoClassGen.Attributes.AutoDecorAttribute"; | ||
|
||
//private const string AttributeValueMetadataNameDecor = "AutoDecor"; | ||
/// <summary> | ||
/// 泛型AutoDecorAttribute | ||
/// </summary> | ||
private const string AttributeMetadataNameDecorG = "Biwen.AutoClassGen.Attributes.AutoDecorAttribute`1"; | ||
|
||
|
||
|
||
|
||
public void Initialize(IncrementalGeneratorInitializationContext context) | ||
{ | ||
|
||
|
@@ -79,6 +90,26 @@ public void Initialize(IncrementalGeneratorInitializationContext context) | |
|
||
#endregion | ||
|
||
|
||
#region AutoDecorAttribute | ||
|
||
var nodesDecor = context.SyntaxProvider.ForAttributeWithMetadataName( | ||
AttributeMetadataNameDecor, | ||
(context, attributeSyntax) => true, | ||
(syntaxContext, _) => syntaxContext.TargetSymbol).Collect(); | ||
|
||
var nodesDecorG = context.SyntaxProvider.ForAttributeWithMetadataName( | ||
AttributeMetadataNameDecorG, | ||
(context, attributeSyntax) => true, | ||
(syntaxContext, _) => syntaxContext.TargetSymbol).Collect(); | ||
|
||
IncrementalValueProvider<((Compilation, ImmutableArray<ISymbol>), ImmutableArray<ISymbol>)> compilationAndTypesDecor = | ||
context.CompilationProvider.Combine(nodesDecor).Combine(nodesDecorG); | ||
|
||
context.RegisterSourceOutput(compilationAndTypesDecor, static (spc, source) => | ||
HandleAnnotatedNodesDecor(source.Item1.Item1, source.Item1.Item2, source.Item2, spc)); | ||
|
||
#endregion | ||
} | ||
|
||
|
||
|
@@ -428,7 +459,7 @@ void GenProperty(TypeSyntax @type) | |
/// <param name="context"></param> | ||
private static void HandleAnnotatedNodesDtoG(Compilation compilation, ImmutableArray<SyntaxNode> nodes, SourceProductionContext context) | ||
{ | ||
if(nodes.Length == 0) return; | ||
if (nodes.Length == 0) return; | ||
|
||
StringBuilder envStringBuilder = new(); | ||
|
||
|
@@ -592,6 +623,116 @@ void GenProperty(TypeSyntax @type) | |
} | ||
|
||
|
||
private static void HandleAnnotatedNodesDecor(Compilation compilation, ImmutableArray<ISymbol> nodes, ImmutableArray<ISymbol> nodes2, SourceProductionContext context) | ||
{ | ||
if (nodes.Length == 0) return; | ||
|
||
IList<KeyValuePair<string, string>> ofImpls = []; | ||
// (普通特性)获取所有实现类 | ||
foreach (var node in nodes) | ||
{ | ||
var tName = node.OriginalDefinition.ToDisplayString(); | ||
foreach (var item in node.GetAttributes().Where(x => x.AttributeClass?.MetadataName == "AutoDecorAttribute")) | ||
{ | ||
var attributeSyntax = item?.ApplicationSyntaxReference?.GetSyntax() as AttributeSyntax; | ||
|
||
if (attributeSyntax?.ArgumentList?.Arguments[0].Expression is TypeOfExpressionSyntax implNameSyntax) | ||
{ | ||
var implNameStr = implNameSyntax.Type.ToString(); | ||
var symbol = compilation.GetSymbolsWithName(implNameStr, SymbolFilter.Type); | ||
|
||
if (symbol?.Any() is true) | ||
{ | ||
var implName = symbol.First().ToDisplayString(); | ||
implNameStr = implName; | ||
|
||
ofImpls.Add(new KeyValuePair<string, string>(tName, implName)); | ||
} | ||
} | ||
} | ||
} | ||
// (泛型特性)获取所有实现类 | ||
foreach (var node in nodes2) | ||
{ | ||
var tName = node.OriginalDefinition.ToDisplayString(); | ||
foreach (var item in node.GetAttributes().Where(x => x.AttributeClass?.MetadataName == "AutoDecorAttribute`1")) | ||
{ | ||
var attributeSyntax = item?.ApplicationSyntaxReference?.GetSyntax() as AttributeSyntax; | ||
|
||
if (attributeSyntax?.Name is GenericNameSyntax genericNameSyntax) | ||
{ | ||
var implNameStr = genericNameSyntax.TypeArgumentList.Arguments[0].ToString(); | ||
var symbol = compilation.GetSymbolsWithName(genericNameSyntax.TypeArgumentList.Arguments[0].ToString(), SymbolFilter.Type); | ||
|
||
if (symbol?.Any() is true) | ||
{ | ||
var implName = symbol.First().ToDisplayString(); | ||
implNameStr = implName; | ||
|
||
ofImpls.Add(new KeyValuePair<string, string>(tName, implName)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (ofImpls.Count == 0) | ||
{ | ||
return; | ||
} | ||
|
||
//namespace Microsoft.Extensions.DependencyInjection | ||
// { | ||
// public static class AutoAopExtensions | ||
// { | ||
// /// <summary> | ||
// /// AddAutoDecor | ||
// /// </summary> | ||
// /// <param name="services"></param> | ||
// /// <returns></returns> | ||
// public static IServiceCollection AddAutoDecor(this IServiceCollection services) | ||
// { | ||
// services.Decorate<IHelloService, IHelloServiceDecorate>(); | ||
// services.Decorate<IHelloService, IHelloServiceDecorate2>(); | ||
// return services; | ||
// } | ||
// } | ||
// } | ||
|
||
StringBuilder envStringBuilder = new(); | ||
envStringBuilder.AppendLine("// <auto-generated />"); | ||
envStringBuilder.AppendLine("// author:[email protected] 万雅虎"); | ||
envStringBuilder.AppendLine("// issue:https://github.com/vipwan/Biwen.AutoClassGen/issues"); | ||
envStringBuilder.AppendLine("// 如果你在使用中遇到问题,请第一时间issue,谢谢!"); | ||
envStringBuilder.AppendLine("// This file is generated by Biwen.AutoClassGen.SourceGenerator"); | ||
envStringBuilder.AppendLine(); | ||
envStringBuilder.AppendLine("#pragma warning disable"); | ||
envStringBuilder.AppendLine("namespace Microsoft.Extensions.DependencyInjection"); | ||
envStringBuilder.AppendLine("{"); | ||
envStringBuilder.AppendLine("public static class AutoDecorExtensions"); | ||
envStringBuilder.AppendLine("{"); | ||
envStringBuilder.AppendLine("/// <summary>"); | ||
envStringBuilder.AppendLine("/// AddAutoDecor"); | ||
envStringBuilder.AppendLine("/// </summary>"); | ||
envStringBuilder.AppendLine("public static IServiceCollection AddAutoDecor(this IServiceCollection services)"); | ||
envStringBuilder.AppendLine("{"); | ||
// decor | ||
foreach (var item in ofImpls) | ||
{ | ||
envStringBuilder.AppendLine($"services.Decorate<{item.Key}, {item.Value}>();"); | ||
} | ||
envStringBuilder.AppendLine("return services;"); | ||
envStringBuilder.AppendLine("}"); | ||
envStringBuilder.AppendLine("}"); | ||
envStringBuilder.AppendLine("}"); | ||
envStringBuilder.AppendLine("#pragma warning restore"); | ||
|
||
var envSource = envStringBuilder.ToString(); | ||
// format: | ||
envSource = FormatContent(envSource); | ||
context.AddSource($"Biwen.AutoClassGenDecor.g.cs", SourceText.From(envSource, Encoding.UTF8)); | ||
} | ||
|
||
|
||
#region Template | ||
|
||
public static readonly string MapperTemplate = $@" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
namespace Biwen.AutoClassGen.TestConsole.Decors | ||
{ | ||
|
||
[AutoDecor(typeof(HelloServiceDecor1))] | ||
[AutoDecor<HelloServiceDecor2>] | ||
public interface IHelloService | ||
{ | ||
string SayHello(string name); | ||
} | ||
|
||
/// <summary> | ||
/// implement IHelloService | ||
/// </summary> | ||
[AutoDecor<HelloServiceDecor1>] | ||
public class HelloService : IHelloService | ||
{ | ||
public string SayHello(string name) | ||
{ | ||
return $"Hello {name}"; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// decor IHelloService | ||
/// </summary> | ||
public class HelloServiceDecor1 : HelloService | ||
{ | ||
private readonly HelloService _helloService; | ||
|
||
public HelloServiceDecor1(HelloService helloService) | ||
{ | ||
_helloService = helloService; | ||
} | ||
|
||
public new string SayHello(string name) | ||
{ | ||
Console.WriteLine($"Hello {name} from HelloServiceDecor1"); | ||
return _helloService.SayHello(name); | ||
} | ||
} | ||
/// <summary> | ||
/// decor IHelloService 2 | ||
/// </summary> | ||
public class HelloServiceDecor2 : IHelloService | ||
{ | ||
private readonly IHelloService _helloService; | ||
|
||
public HelloServiceDecor2(IHelloService helloService) | ||
{ | ||
_helloService = helloService; | ||
} | ||
|
||
public string SayHello(string name) | ||
{ | ||
Console.WriteLine($"Hello {name} from HelloServiceDecor2"); | ||
return _helloService.SayHello(name); | ||
} | ||
} | ||
|
||
|
||
} |
Oops, something went wrong.