using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.Linq; namespace XFEExtension.NetCore.AutoConfig.Analyzer.Generator; [Generator] public class ProfilePropertyAutoGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { context.RegisterSourceOutput(context.CompilationProvider, Generate); } public void Generate(SourceProductionContext context, Compilation compilation) { var syntaxTrees = compilation.SyntaxTrees; foreach (var syntaxTree in syntaxTrees) { var root = syntaxTree.GetRoot(); var classDeclarations = GetClassDeclarations(root); var usingDirectives = root.DescendantNodes().OfType().ToArray(); var fileScopedNamespaceDeclarationSyntax = GetFileScopedNamespaceDeclaration(root); foreach (var classDeclaration in classDeclarations) { var fieldDeclarationSyntaxes = GetFieldDeclarations(classDeclaration); if (fieldDeclarationSyntaxes is null || !fieldDeclarationSyntaxes.Any()) { continue; } var className = classDeclaration.Identifier.ValueText; var attributeSyntax = SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Attribute(SyntaxFactory.ParseName("global::XFEExtension.NetCore.AutoConfig.ProfileFieldAutoGenerateAttribute")))); var staticProperties = new List(); var instanceProperties = new List(); var basicProfileMembers = new List(); var methodMembers = new List(); var initializerBlockStatements = new List() { SyntaxFactory.ParseStatement($"this.SetProfileOperation();"), SyntaxFactory.ParseStatement($@"this.CurrentProfilePath = $""{{ProfilePath}}{{(string.IsNullOrEmpty(ProfileExtension) ? this.CurrentProfileExtension : ProfileExtension)}}"";") }; foreach (var fieldDeclarationSyntax in fieldDeclarationSyntaxes) { var variableDeclaration = fieldDeclarationSyntax.Declaration.Variables.First(); var fieldName = variableDeclaration.Identifier.Text; var propertyName = fieldName[0] == '_' ? fieldName[1].ToString().ToUpper() + fieldName.Substring(2) : fieldName[0].ToString().ToUpper() + fieldName.Substring(1); var propertyType = fieldDeclarationSyntax.Declaration.Type; var instancePropertyName = $"Instance{propertyName}"; var getMethodName = $"Get{propertyName}Property"; var setMethodName = $"Set{propertyName}Property"; initializerBlockStatements.Add(SyntaxFactory.ParseStatement($"this.PropertyInfoDictionary.Add(nameof({propertyName}), typeof({propertyType.ToString().Replace("?", string.Empty).Replace(" ", string.Empty)}));")); initializerBlockStatements.Add(SyntaxFactory.ParseStatement($"this.PropertySetFuncDictionary.Add(nameof({propertyName}), (value) => this.{fieldName} = ({propertyType.ToString().Replace("?", string.Empty).Replace(" ", string.Empty)})value);")); initializerBlockStatements.Add(SyntaxFactory.ParseStatement($"this.PropertyGetFuncDictionary.Add(nameof({propertyName}), () => this.{fieldName});")); GetProfilePropertyAttributeList(fieldDeclarationSyntax).ForEach(attribute => { if (attribute.ArgumentList is null) { return; } var argument = attribute.ArgumentList.Arguments.First(); if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax) { propertyName = literalExpressionSyntax.Token.ValueText; } }); #region Trivia头 var triviaText = $@"/// /// /// 是根据 自动生成的静态属性

/// 方法已生成以下代码: ○ ;
"; #endregion var getExpressionStatements = new List() { SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{getMethodName}()")).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) }; if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddGetAttribute)) { GetProfilePropertyAddGetAttributeList(fieldDeclarationSyntax).ForEach(attribute => { if (attribute.ArgumentList is null) { return; } var argument = attribute.ArgumentList.Arguments.First(); var funcText = string.Empty; if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax) funcText = literalExpressionSyntax.Token.ValueText; if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax) funcText = interpolatedStringExpressionSyntax.Contents.ToString(); if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax) funcText = invocationExpressionSyntax.GetText().ToString(); getExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))); #region Get方法注释 triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "
").Replace("return", "").Replace(fieldName, $"")};
"; #endregion }); } else { getExpressionStatements.Add(SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression($"Current.{fieldName}"))); #region Get方默认注释 triviaText += $@" /// ○ ;"; #endregion } #region Get方法尾及Set方法头注释 triviaText += $@" ///
///
/// 方法已生成以下代码: ○ ", "}")})""/>;
"; #endregion var setExpressionStatements = new List() { SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{setMethodName}(ref value)")).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) }; if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddSetAttribute)) { GetProfilePropertyAddSetAttributeList(fieldDeclarationSyntax).ForEach(attribute => { if (attribute.ArgumentList is null) { return; } var argument = attribute.ArgumentList.Arguments.First(); var funcText = string.Empty; if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax) funcText = literalExpressionSyntax.Token.ValueText; else if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax) funcText = interpolatedStringExpressionSyntax.Contents.ToString(); else if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax) funcText = invocationExpressionSyntax.GetText().ToString(); setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))); #region Set方法注释 triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "
").Replace("<", "<").Replace(">", ">").Replace(fieldName, $" < seealso langword=\"{fieldName}\"/>").Replace("value", "")};
"; #endregion }); } else { setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"Current.{fieldName} = value"))); #region Set方法默认注释 triviaText += $@" /// ○ = ;
"; #endregion } setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{className}.SaveProfile()"))); #region Set方法中的保存方法的注释 triviaText += $@" /// ○ "; #endregion #region Trivia尾 triviaText += @" ///
///
"; #endregion var staticProperty = SyntaxFactory.PropertyDeclaration(propertyType, propertyName) .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .AddAttributeLists(attributeSyntax) .WithAccessorList(SyntaxFactory.AccessorList( SyntaxFactory.List( [ SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithBody(SyntaxFactory.Block(getExpressionStatements)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) .WithBody(SyntaxFactory.Block(setExpressionStatements)) ]))) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText)); var getMethod = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), getMethodName) .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 当且仅当 被获取时触发此方法 /// ")); var setMethod = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), setMethodName) .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword))) .AddParameterListParameters(SyntaxFactory.Parameter(SyntaxFactory.Identifier("value")).WithType(propertyType).WithModifiers([SyntaxFactory.Token(SyntaxKind.RefKeyword)])) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 当且仅当 被赋值时触发此方法 /// ")); methodMembers.Add(getMethod); methodMembers.Add(setMethod); instanceProperties.Add(SyntaxFactory.PropertyDeclaration(propertyType, instancePropertyName) .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) .AddAttributeLists(attributeSyntax) .WithAccessorList(SyntaxFactory.AccessorList( SyntaxFactory.List( [ SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithExpressionBody(SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression($"{fieldName}"))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) .WithExpressionBody(SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression($"{fieldName} = value"))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) ]))) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// /// 是根据 自动生成的实例属性 /// "))); staticProperties.Add(staticProperty.NormalizeWhitespace()); } basicProfileMembers.Add(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "Initialize") .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.OverrideKeyword))) .WithBody(SyntaxFactory.Block(initializerBlockStatements))); var basicProfileClassSyntaxTree = GenerateBasicProfileClassSyntaxTree(classDeclaration, usingDirectives, basicProfileMembers, fileScopedNamespaceDeclarationSyntax); var profileStaticPropertyClassSyntaxTree = GenerateProfileStaticPropertyClassSyntaxTree(classDeclaration, usingDirectives, staticProperties, fileScopedNamespaceDeclarationSyntax); var profileInstancePropertyClassSyntaxTree = GenerateProfileInstancePropertyClassSyntaxTree(classDeclaration, usingDirectives, instanceProperties, fileScopedNamespaceDeclarationSyntax); var profileMethodClassSyntaxTree = GenerateProfileMethodClassSyntaxTree(classDeclaration, usingDirectives, methodMembers, fileScopedNamespaceDeclarationSyntax); context.AddSource($"{className}.g.cs", basicProfileClassSyntaxTree.ToString()); context.AddSource($"{className}.StaticProperties.g.cs", profileStaticPropertyClassSyntaxTree.ToString()); context.AddSource($"{className}.InstanceProperties.g.cs", profileInstancePropertyClassSyntaxTree.ToString()); context.AddSource($"{className}.Methods.g.cs", profileMethodClassSyntaxTree.ToString()); } } } public static bool IsProfilePropertyAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfileProperty"); public static List GetProfilePropertyAttributeList(FieldDeclarationSyntax fieldDeclaration) => [.. fieldDeclaration.AttributeLists.Where(IsProfilePropertyAttribute).SelectMany(attributeList => attributeList.Attributes)]; public static bool IsAutoLoadProfileAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "AutoLoadProfile"); public static List GetAutoLoadProfileAttribute(FieldDeclarationSyntax fieldDeclaration) => [.. fieldDeclaration.AttributeLists.Where(IsAutoLoadProfileAttribute).SelectMany(attributeList => attributeList.Attributes)]; public static bool IsProfilePropertyAddGetAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfilePropertyAddGet"); public static List GetProfilePropertyAddGetAttributeList(FieldDeclarationSyntax fieldDeclaration) => [.. fieldDeclaration.AttributeLists.Where(IsProfilePropertyAddGetAttribute).SelectMany(attributeList => attributeList.Attributes)]; public static bool IsProfilePropertyAddSetAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfilePropertyAddSet"); public static List GetProfilePropertyAddSetAttributeList(FieldDeclarationSyntax fieldDeclaration) => [.. fieldDeclaration.AttributeLists.Where(IsProfilePropertyAddSetAttribute).SelectMany(attributeList => attributeList.Attributes)]; public static FileScopedNamespaceDeclarationSyntax GetFileScopedNamespaceDeclaration(SyntaxNode rootNode) { var namespaceResults = rootNode.DescendantNodes().OfType(); if (namespaceResults != null && namespaceResults.Count() > 0) return namespaceResults.First(); return null; } public static IEnumerable GetFieldDeclarations(ClassDeclarationSyntax classDeclaration) => classDeclaration.DescendantNodes() .OfType() .Where(fieldDeclarationSyntax => fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAttribute) && !fieldDeclarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword)); public static IEnumerable GetClassDeclarations(SyntaxNode rootNode) => rootNode.DescendantNodes() .OfType() .Where(classDeclaration => classDeclaration.BaseList is not null && classDeclaration.BaseList.Types.Any(type => type.ToString() == "XFEProfile")); private static MemberDeclarationSyntax GetClass(ClassDeclarationSyntax classDeclaration, ClassDeclarationSyntax profileClassDeclaration, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax) { if (fileScopedNamespaceDeclarationSyntax is null) { var namespaceDeclaration = classDeclaration.FirstAncestorOrSelf(); if (namespaceDeclaration is null) return profileClassDeclaration; else return SyntaxFactory.NamespaceDeclaration(namespaceDeclaration.Name) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia("#pragma warning disable\n#nullable enable")) .AddMembers(profileClassDeclaration); } else { return SyntaxFactory.FileScopedNamespaceDeclaration(fileScopedNamespaceDeclarationSyntax.Name) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia("#pragma warning disable\n#nullable enable")) .AddMembers(profileClassDeclaration); } } private static SyntaxTree GenerateBasicProfileClassSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, List memberDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax) { var className = classDeclaration.Identifier.ValueText; var staticConstructorSyntax = SyntaxFactory.ConstructorDeclaration(className) .AddModifiers(SyntaxFactory.Token(SyntaxKind.StaticKeyword)) .WithBody(SyntaxFactory.Block( SyntaxFactory.ParseStatement($"Current = new();"), SyntaxFactory.ParseStatement($"Current.Initialize();"), SyntaxFactory.ParseStatement($"{className}.LoadProfile();") )); if (classDeclaration.AttributeLists.Any(IsAutoLoadProfileAttribute)) { var autoLoadProfileAttribute = classDeclaration.AttributeLists.First(IsAutoLoadProfileAttribute).Attributes.First(); if (autoLoadProfileAttribute.ArgumentList != null) { var argument = autoLoadProfileAttribute.ArgumentList.Arguments.First(); if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax && literalExpressionSyntax.Token.ValueText == "true") { memberDeclarationSyntaxes.Add(staticConstructorSyntax); } } else { memberDeclarationSyntaxes.Add(staticConstructorSyntax); } } else { memberDeclarationSyntaxes.Add(staticConstructorSyntax); } memberDeclarationSyntaxes.Add(SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(className), "Current") .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Attribute(SyntaxFactory.ParseName("global::XFEExtension.NetCore.AutoConfig.ProfileInstanceAttribute"))))) .WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List( [ SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) ]))) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 该配置文件的实例

/// 的配置文件类的实例数据 ///
"))); memberDeclarationSyntaxes.Add(SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName("string"), "ProfilePath") .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List( [ SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) ]))) .WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression($@"$""{{(global::XFEExtension.NetCore.AutoConfig.XFEProfile.ProfilesDefaultPath)}}\\{{nameof({className})}}"""))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 该配置文件的存储位置

/// 的配置文件存储路径(不包含文件扩展名,如需设置扩展名,请查阅 ) ///
"))); memberDeclarationSyntaxes.Add(SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName("string"), "ProfileExtension") .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List( [ SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) ]))) .WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("string.Empty"))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 该配置文件的文件扩展名

/// 当为空时, 将根据配置文件类型自动选择合适的扩展名(.xpf .json .xml等) ///
"))); memberDeclarationSyntaxes.Add(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "LoadProfile") .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .WithExpressionBody(SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression($"Current = Current.InstanceLoadProfile() as {className}"))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 配置文件加载方法

/// 是根据 生成的加载配置文件的静态方法 ///
"))); memberDeclarationSyntaxes.Add(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "SaveProfile") .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .WithExpressionBody(SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression($"Current.InstanceSaveProfile()"))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 配置文件保存方法

/// 是根据 生成的保存配置文件的静态方法 ///
"))); memberDeclarationSyntaxes.Add(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "DeleteProfile") .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .WithExpressionBody(SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression($"Current.InstanceDeleteProfile()"))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 配置文件删除方法

/// 是根据 生成的删除配置文件的静态方法 ///
"))); memberDeclarationSyntaxes.Add(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("string"), "ExportProfile") .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .WithExpressionBody(SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression($"Current.InstanceExportProfile()"))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 配置文件导出方法

/// 是根据 生成的导出配置文件的静态方法 ///
/// 导出的配置文件字符串 "))); memberDeclarationSyntaxes.Add(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "ImportProfile") .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .AddParameterListParameters(SyntaxFactory.Parameter(SyntaxFactory.Identifier("profileString")).WithType(SyntaxFactory.ParseTypeName("string"))) .WithExpressionBody(SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression($"Current = Current.InstanceImportProfile(profileString) as {className}"))) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// /// 配置文件导入方法

/// 是根据 生成的导入配置文件的静态方法 ///
/// 待导入配置文件字符串 "))); var profileClass = SyntaxFactory.ClassDeclaration(className) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword)) .AddMembers([.. memberDeclarationSyntaxes]) .NormalizeWhitespace(); var profileClassCompilationUnit = SyntaxFactory.CompilationUnit() .AddUsings(usingDirectiveSyntaxes) .AddMembers(GetClass(classDeclaration, profileClass, fileScopedNamespaceDeclarationSyntax)) .NormalizeWhitespace(); return SyntaxFactory.SyntaxTree(profileClassCompilationUnit); } private static SyntaxTree GenerateProfileStaticPropertyClassSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, List propertyDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax) { var className = classDeclaration.Identifier.ValueText; var triviaText = $@"/// /// 已自动实现以下属性:
/// "; triviaText += string.Join("
\n", propertyDeclarationSyntaxes.Select(propertyDeclarationSyntax => $"/// ○ ")) + "\n///

\n/// 来自\n///
\n"; var memberDeclarationSyntaxes = new List(); memberDeclarationSyntaxes.AddRange(propertyDeclarationSyntaxes); var profileClass = SyntaxFactory.ClassDeclaration(className) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword)) .AddMembers([.. memberDeclarationSyntaxes]) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText)) .NormalizeWhitespace(); var profileClassCompilationUnit = SyntaxFactory.CompilationUnit() .AddUsings(usingDirectiveSyntaxes) .AddMembers(GetClass(classDeclaration, profileClass, fileScopedNamespaceDeclarationSyntax)) .NormalizeWhitespace(); return SyntaxFactory.SyntaxTree(profileClassCompilationUnit); } private static SyntaxTree GenerateProfileInstancePropertyClassSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, List propertyDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax) { var className = classDeclaration.Identifier.ValueText; var memberDeclarationSyntaxes = new List(); memberDeclarationSyntaxes.AddRange(propertyDeclarationSyntaxes); var profileClass = SyntaxFactory.ClassDeclaration(className) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword)) .AddMembers([.. memberDeclarationSyntaxes]) .NormalizeWhitespace(); var profileClassCompilationUnit = SyntaxFactory.CompilationUnit() .AddUsings(usingDirectiveSyntaxes) .AddMembers(GetClass(classDeclaration, profileClass, fileScopedNamespaceDeclarationSyntax)) .NormalizeWhitespace(); return SyntaxFactory.SyntaxTree(profileClassCompilationUnit); } private static SyntaxTree GenerateProfileMethodClassSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, List memberDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax) { var className = classDeclaration.Identifier.ValueText; var profileClass = SyntaxFactory.ClassDeclaration(className) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword)) .AddMembers([.. memberDeclarationSyntaxes]) .NormalizeWhitespace(); var profileClassCompilationUnit = SyntaxFactory.CompilationUnit() .AddUsings(usingDirectiveSyntaxes) .AddMembers(GetClass(classDeclaration, profileClass, fileScopedNamespaceDeclarationSyntax)) .NormalizeWhitespace(); return SyntaxFactory.SyntaxTree(profileClassCompilationUnit); } }