XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEExtension.NetCore.AutoImplement

【DLL】自动生成实现类

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFEExtension.NetCore.AutoImplement

完善部分特性识别

1b7dcce
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

5 个文件 +132 -103
Modified XFEExtension.NetCore.AutoImplement.Analyzer/Generator/ImplementAutoGenerator.cs +116 -88
@@ -1,110 +1,138 @@
1 1 using Microsoft.CodeAnalysis;
2 2 using Microsoft.CodeAnalysis.CSharp;
3 3 using Microsoft.CodeAnalysis.CSharp.Syntax;
4 using System.Diagnostics;
4 5 using System.Linq;
6 using System.Threading;
7 using XFEExtension.NetCore.AutoImplement.Analyzer.Model;
5 8
6 namespace XFEExtension.NetCore.AutoImplement.Analyzer.Generator
9 namespace XFEExtension.NetCore.AutoImplement.Analyzer.Generator;
10
11 [Generator]
12 public class ImplementAutoGenerator : IIncrementalGenerator
7 13 {
8 [Generator]
9 public class ImplementAutoGenerator : IIncrementalGenerator
14 public void Initialize(IncrementalGeneratorInitializationContext context)
10 15 {
11 public void Initialize(IncrementalGeneratorInitializationContext context)
12 {
13 context.RegisterSourceOutput(context.CompilationProvider, Generate);
14 }
16 var implementationProvider = context.SyntaxProvider.ForAttributeWithMetadataName("CreateImpl",
17 static (x, _) => x is ClassDeclarationSyntax classDeclaration && classDeclaration.AttributeLists.Any(IsCreateImplAttribute),
18 GetCreateImpl);
19 context.RegisterSourceOutput(implementationProvider.Combine(context.CompilationProvider), Generate);
20 }
15 21
16 public void Generate(SourceProductionContext context, Compilation compilation)
17 {
18 var syntaxTrees = compilation.SyntaxTrees;
19 foreach (var syntaxTree in syntaxTrees)
20 {
21 var root = syntaxTree.GetRoot();
22 var classDeclarations = root.DescendantNodes().OfType<ClassDeclarationSyntax>()
23 .Where(classDeclaration => classDeclaration.AttributeLists.Any(IsCreateImplAttribute));
24 var usingDirectives = root.DescendantNodes().OfType<UsingDirectiveSyntax>().ToArray();
25 FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax = null;
26 var namespaceResults = root.DescendantNodes().OfType<FileScopedNamespaceDeclarationSyntax>();
27 if (namespaceResults != null && namespaceResults.Count() > 0)
28 fileScopedNamespaceDeclarationSyntax = namespaceResults.First();
29 foreach (var classDeclaration in classDeclarations)
30 {
31 var className = classDeclaration.Identifier.ValueText;
32 var implementationSyntaxTree = GenerateImplementationSyntaxTree(classDeclaration, usingDirectives, fileScopedNamespaceDeclarationSyntax, className);
33 context.AddSource($"{className}Impl.g.cs", implementationSyntaxTree.ToString());
34 }
35 }
36 }
22 public void Generate(SourceProductionContext context, (ImplementationInfo? ImplementationInfo, Compilation Compilation) args)
23 {
24 Debugger.Launch();
25 if (args.ImplementationInfo is null)
26 return;
27 var root = args.ImplementationInfo.ClassDeclaration.SyntaxTree.GetRoot();
28 var usingDirectives = root.DescendantNodes().OfType<UsingDirectiveSyntax>().ToArray();
29 FileScopedNamespaceDeclarationSyntax? fileScopedNamespaceDeclarationSyntax = null;
30 var namespaceResults = root.DescendantNodes().OfType<FileScopedNamespaceDeclarationSyntax>();
31 if (namespaceResults != null && namespaceResults.Count() > 0)
32 fileScopedNamespaceDeclarationSyntax = namespaceResults.First();
33 var implementationSyntaxTree = GenerateImplementationSyntaxTree(args.ImplementationInfo.ClassDeclaration, usingDirectives, fileScopedNamespaceDeclarationSyntax, args.ImplementationInfo.TargetClassName, args.ImplementationInfo.Modifiers, args.ImplementationInfo.NameSpace);
34 context.AddSource($"{args.ImplementationInfo.TargetClassName}.g.cs", implementationSyntaxTree.ToString());
35 }
37 36
38 private static bool IsCreateImplAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "CreateImpl");
37 private static bool IsCreateImplAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "CreateImpl");
39 38
40 private static SyntaxTree GenerateImplementationSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax, string className, string[] modifierParameters, string nameSpace)
39 //public static List<AttributeSyntax> GetCreateImplAttributeList(ClassDeclarationSyntax classDeclaration) => [.. classDeclaration.AttributeLists.Where(IsCreateImplAttribute).SelectMany(attributeList => attributeList.Attributes)];
40
41 public static ImplementationInfo? GetCreateImpl(GeneratorAttributeSyntaxContext context, CancellationToken token)
42 {
43 Debugger.Launch();
44 token.ThrowIfCancellationRequested();
45 var classDeclaration = (ClassDeclarationSyntax)context.TargetNode;
46 var attributeData = context.Attributes.FirstOrDefault(ad => ad.AttributeClass?.ToDisplayString() == "CreateImpl");
47 if (attributeData is null)
48 return null;
49 var className = classDeclaration.Identifier.ValueText;
50 var targetClassName = attributeData.NamedArguments.FirstOrDefault(kv => kv.Key == "ClassName").Value.Value as string ?? $"{className}Impl";
51 var nameSpace = attributeData.NamedArguments.FirstOrDefault(kv => kv.Key == "NameSpace").Value.Value as string ?? string.Empty;
52 var modifiers = attributeData.NamedArguments.FirstOrDefault(kv => kv.Key == "Modifiers").Value.Values.Select(v => v.Value?.ToString() ?? string.Empty).Where(s => !string.IsNullOrEmpty(s)).ToArray() ?? [];//此处出现问题
53 if (modifiers.Length == 0)
54 modifiers = ["internal", "partial"];
55 return new ImplementationInfo
56 {
57 ClassDeclaration = classDeclaration,
58 TargetClassName = targetClassName,
59 Modifiers = modifiers,
60 NameSpace = nameSpace
61 };
62 }
63
64 private static SyntaxTree GenerateImplementationSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, FileScopedNamespaceDeclarationSyntax? fileScopedNamespaceDeclarationSyntax, string className, string[] modifierParameters, string nameSpace)
65 {
66 var fatherClassName = classDeclaration.Identifier.ValueText;
67 var modifiers = modifierParameters.Select(modifier => SyntaxFactory.ParseToken(modifier)).ToArray();
68 ClassDeclarationSyntax implementationClass;
69 if (classDeclaration.ParameterList is null)
41 70 {
42 var fatherClassName = classDeclaration.Identifier.ValueText;
43 var modifiers = modifierParameters.Select(modifier => SyntaxFactory.ParseToken(modifier)).ToArray();
44 ClassDeclarationSyntax implementationClass;
45 if (classDeclaration.ParameterList is null)
46 {
47 implementationClass = SyntaxFactory.ClassDeclaration(className)
48 .AddModifiers(modifiers)
49 .AddMembers(classDeclaration.Members.OfType<ConstructorDeclarationSyntax>().Select(constructor =>
50 {
51 return SyntaxFactory.ConstructorDeclaration(className)
52 .AddModifiers(SyntaxFactory.Token(SyntaxKind.InternalKeyword))
53 .WithBody(SyntaxFactory.Block())
54 .WithParameterList(constructor.ParameterList)
55 .WithInitializer(SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(constructor.ParameterList.Parameters.Select(parameter => SyntaxFactory.Argument(SyntaxFactory.IdentifierName(parameter.Identifier)))))));
56 }).ToArray())
57 .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
71 implementationClass = SyntaxFactory.ClassDeclaration(className)
72 .AddModifiers(modifiers)
73 .AddMembers([.. classDeclaration.Members.OfType<ConstructorDeclarationSyntax>().Select(constructor =>
74 {
75 return SyntaxFactory.ConstructorDeclaration(className)
76 .AddModifiers(SyntaxFactory.Token(SyntaxKind.InternalKeyword))
77 .WithBody(SyntaxFactory.Block())
78 .WithParameterList(constructor.ParameterList)
79 .WithInitializer(SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(constructor.ParameterList.Parameters.Select(parameter => SyntaxFactory.Argument(SyntaxFactory.IdentifierName(parameter.Identifier)))))));
80 })])
81 .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
58 82 /// <seealso cref=""{className}""/> 是根据 <seealso cref=""{fatherClassName}""/> 自动生成的实现类
59 83 /// </summary>
60 84 "))
61 .NormalizeWhitespace();
62 }
63 else
64 {
65 implementationClass = SyntaxFactory.ClassDeclaration($"{className}Impl")
66 .AddModifiers(modifiers)
67 .AddMembers(SyntaxFactory.ConstructorDeclaration($"{className}Impl")
68 .AddModifiers(SyntaxFactory.Token(SyntaxKind.InternalKeyword))
69 .WithBody(SyntaxFactory.Block())
70 .WithParameterList(classDeclaration.ParameterList)
71 .WithInitializer(SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(classDeclaration.ParameterList.Parameters.Select(parameter => SyntaxFactory.Argument(SyntaxFactory.IdentifierName(parameter.Identifier))))))))
72 .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
85 .NormalizeWhitespace();
86 }
87 else
88 {
89 implementationClass = SyntaxFactory.ClassDeclaration($"{className}Impl")
90 .AddModifiers(modifiers)
91 .AddMembers(SyntaxFactory.ConstructorDeclaration($"{className}Impl")
92 .AddModifiers(SyntaxFactory.Token(SyntaxKind.InternalKeyword))
93 .WithBody(SyntaxFactory.Block())
94 .WithParameterList(classDeclaration.ParameterList)
95 .WithInitializer(SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(classDeclaration.ParameterList.Parameters.Select(parameter => SyntaxFactory.Argument(SyntaxFactory.IdentifierName(parameter.Identifier))))))))
96 .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
73 97 /// <seealso cref=""{className}Impl""/> 是根据 <seealso cref=""{className}""/> 自动生成的实现类
74 98 /// </summary>
75 99 "))
76 .NormalizeWhitespace();
77 }
78 if (classDeclaration.TypeParameterList is TypeParameterListSyntax typeParameterListSyntax && typeParameterListSyntax.Parameters.Count > 0)
79 {
80 implementationClass = implementationClass.AddTypeParameterListParameters(typeParameterListSyntax.Parameters.ToArray())
81 .AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName($"{className}{typeParameterListSyntax}")))
82 .AddConstraintClauses(classDeclaration.ConstraintClauses.ToArray());
83 }
84 else
85 {
86 implementationClass = implementationClass.AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(className)));
87 }
88 MemberDeclarationSyntax memberDeclaration;
89 if (fileScopedNamespaceDeclarationSyntax is null)
90 {
91 var namespaceDeclaration = classDeclaration.FirstAncestorOrSelf<NamespaceDeclarationSyntax>();
92 if (namespaceDeclaration is null)
93 memberDeclaration = implementationClass;
94 else
95 memberDeclaration = SyntaxFactory.NamespaceDeclaration(namespaceDeclaration.Name)
96 .AddMembers(implementationClass);
97 }
100 .NormalizeWhitespace();
101 }
102 if (classDeclaration.TypeParameterList is TypeParameterListSyntax typeParameterListSyntax && typeParameterListSyntax.Parameters.Count > 0)
103 {
104 implementationClass = implementationClass.AddTypeParameterListParameters([.. typeParameterListSyntax.Parameters])
105 .AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName($"{className}{typeParameterListSyntax}")))
106 .AddConstraintClauses([.. classDeclaration.ConstraintClauses]);
107 }
108 else
109 {
110 implementationClass = implementationClass.AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(className)));
111 }
112 MemberDeclarationSyntax memberDeclaration;
113 if (nameSpace != string.Empty)
114 {
115 memberDeclaration = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(nameSpace))
116 .AddMembers(implementationClass);
117 }
118 else if (fileScopedNamespaceDeclarationSyntax is null)
119 {
120 var namespaceDeclaration = classDeclaration.FirstAncestorOrSelf<NamespaceDeclarationSyntax>();
121 if (namespaceDeclaration is null)
122 memberDeclaration = implementationClass;
98 123 else
99 {
100 memberDeclaration = SyntaxFactory.FileScopedNamespaceDeclaration(fileScopedNamespaceDeclarationSyntax.Name)
124 memberDeclaration = SyntaxFactory.NamespaceDeclaration(namespaceDeclaration.Name)
101 125 .AddMembers(implementationClass);
102 }
103 var implementationCompilationUnit = SyntaxFactory.CompilationUnit()
104 .AddUsings(usingDirectiveSyntaxes)
105 .AddMembers(memberDeclaration)
106 .NormalizeWhitespace();
107 return SyntaxFactory.SyntaxTree(implementationCompilationUnit);
108 126 }
127 else
128 {
129 memberDeclaration = SyntaxFactory.FileScopedNamespaceDeclaration(fileScopedNamespaceDeclarationSyntax.Name)
130 .AddMembers(implementationClass);
131 }
132 var implementationCompilationUnit = SyntaxFactory.CompilationUnit()
133 .AddUsings(usingDirectiveSyntaxes)
134 .AddMembers(memberDeclaration)
135 .NormalizeWhitespace();
136 return SyntaxFactory.SyntaxTree(implementationCompilationUnit);
109 137 }
110 138 }
Added XFEExtension.NetCore.AutoImplement.Analyzer/Model/ImplementationInfo.cs +11 -0
@@ -0,0 +1,11 @@
1 using Microsoft.CodeAnalysis.CSharp.Syntax;
2
3 namespace XFEExtension.NetCore.AutoImplement.Analyzer.Model;
4
5 public class ImplementationInfo
6 {
7 public ClassDeclarationSyntax ClassDeclaration { get; set; }
8 public string TargetClassName { get; set; } = string.Empty;
9 public string[] Modifiers { get; set; } = [];
10 public string NameSpace { get; set; } = string.Empty;
11 }
Modified XFEExtension.NetCore.AutoImplement.Analyzer/XFEExtension.NetCore.AutoImplement.Analyzer.csproj +2 -0
@@ -2,6 +2,8 @@
2 2
3 3 <PropertyGroup>
4 4 <TargetFramework>netstandard2.0</TargetFramework>
5 <LangVersion>13.0</LangVersion>
6 <Nullable>enable</Nullable>
5 7 </PropertyGroup>
6 8
7 9 <PropertyGroup>
Modified XFEExtension.NetCore.AutoImplement.Test/Program.cs +1 -4
@@ -1,5 +1,2 @@
1 1 // See https://aka.ms/new-console-template for more information
2 using XFEExtension.NetCore.AutoImplement.Test;
3
4 Console.WriteLine("Hello, World!");
5 var myClass = new MyTestClassImpl<string, Program>("123", new());
2 Console.WriteLine("Hello, World!");
Modified XFEExtension.NetCore.AutoImplement/CreateImpl.cs +2 -11
@@ -8,15 +8,6 @@ public class CreateImpl : Attribute
8 8 {
9 9 public string? ClassName { get; set; }
10 10 public string? NameSpace { get; set; }
11 public string[]? Modifier { get; set; }
11 public string[]? Modifiers { get; set; }
12 12 public CreateImpl() { }
13 public CreateImpl(string className)
14 {
15 ClassName = className;
16 }
17 public CreateImpl(string className, params string[] modifier)
18 {
19 ClassName = className;
20 Modifier = modifier;
21 }
22 }
13 }