diff --git a/Biwen.AutoClassGen.Attributes/AutoDtoAttribute.cs b/Biwen.AutoClassGen.Attributes/AutoDtoAttribute.cs
new file mode 100644
index 0000000..fae4f49
--- /dev/null
+++ b/Biwen.AutoClassGen.Attributes/AutoDtoAttribute.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Biwen.AutoClassGen.Attributes
+{
+ ///
+ /// 自动创建Dto
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
+ public class AutoDtoAttribute : Attribute
+ {
+ ///
+ /// 从指定类型创建
+ ///
+ public Type FromType { get; private set; }
+
+ public string[] ExcludeProps { get; private set; }
+
+ public AutoDtoAttribute(Type fromType, params string[] excludeProps)
+ {
+ FromType = fromType;
+ ExcludeProps = excludeProps;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Biwen.AutoClassGen.Gen/SourceGenerator.cs b/Biwen.AutoClassGen.Gen/SourceGenerator.cs
index 7cb83f0..88c06a3 100644
--- a/Biwen.AutoClassGen.Gen/SourceGenerator.cs
+++ b/Biwen.AutoClassGen.Gen/SourceGenerator.cs
@@ -2,6 +2,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@@ -19,10 +20,18 @@ public class SourceGenerator : IIncrementalGenerator
const string AttributeMetadataName = "Biwen.AutoClassGen.Attributes.AutoGenAttribute";
const string AttributeValueMetadataName = "AutoGen";
+ const string AttributeMetadataName_Dto = "Biwen.AutoClassGen.Attributes.AutoDtoAttribute";
+ const string AttributeValueMetadataName_Dto = "AutoDto";
+
+
public void Initialize(IncrementalGeneratorInitializationContext context)
{
+
+ #region AutoGenAttribute
+
+
var nodes = context.SyntaxProvider.ForAttributeWithMetadataName(
AttributeMetadataName,
(context, attributeSyntax) => true,
@@ -33,8 +42,30 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
context.RegisterSourceOutput(compilationAndTypes, static (spc, source) => HandleAnnotatedNodes(source.Item1, source.Item2, spc));
+ #endregion
+
+ #region AutoDtoAttribute
+
+ var nodesDto = context.SyntaxProvider.ForAttributeWithMetadataName(
+ AttributeMetadataName_Dto,
+ (context, attributeSyntax) => true,
+ (syntaxContext, _) => syntaxContext.TargetNode).Collect();
+
+ IncrementalValueProvider<(Compilation, ImmutableArray)> compilationAndTypesDto =
+ context.CompilationProvider.Combine(nodesDto);
+
+ context.RegisterSourceOutput(compilationAndTypesDto, static (spc, source) => HandleAnnotatedNodesDto(source.Item1, source.Item2, spc));
+
+ #endregion
}
+
+ ///
+ /// Gen AutoGenAttribute
+ ///
+ ///
+ ///
+ ///
private static void HandleAnnotatedNodes(Compilation compilation, ImmutableArray nodes, SourceProductionContext context)
{
var sb = new StringBuilder();
@@ -174,6 +205,160 @@ void genProperty(TypeSyntax @interfaceType)
}
}
+ ///
+ /// Gen AutoDtoAttribute
+ ///
+ ///
+ ///
+ ///
+ private static void HandleAnnotatedNodesDto(Compilation compilation, ImmutableArray nodes, SourceProductionContext context)
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine("// ");
+ sb.AppendLine("// author:vipwan@outlook.com 万雅虎");
+ sb.AppendLine("// issue:https://github.com/vipwan/Biwen.AutoClassGen/issues");
+ sb.AppendLine("// 如果你在使用中遇到问题,请第一时间issue,谢谢!");
+ sb.AppendLine("// This file is generated by Biwen.AutoClassGen.SourceGenerator");
+ sb.AppendLine();
+ sb.AppendLine("using System;");
+ sb.AppendLine("using System.Collections.Generic;");
+ sb.AppendLine("using System.Text;");
+ sb.AppendLine("using System.Threading.Tasks;");
+
+ sb.AppendLine();
+ sb.AppendLine("$namespace");
+ sb.AppendLine();
+
+ sb.AppendLine("#pragma warning disable");
+ sb.AppendLine("namespace $ni");
+ sb.AppendLine("{");
+ sb.AppendLine("$classes");
+ sb.AppendLine("}");
+ sb.AppendLine("#pragma warning restore");
+
+ string classTemp = $"public partial class $className {{ $body }}";
+
+ foreach (ClassDeclarationSyntax node in nodes.AsEnumerable().Cast())
+ {
+
+
+ AttributeSyntax? attributeSyntax = null;
+ foreach (var attr in node.AttributeLists.AsEnumerable())
+ {
+ var attrName = attr.Attributes.FirstOrDefault()?.Name.ToString();
+ if (attrName == AttributeValueMetadataName_Dto)
+ {
+ attributeSyntax = attr.Attributes.First(x => x.Name.ToString() == AttributeValueMetadataName_Dto);
+ break;
+ }
+ }
+ if (attributeSyntax == null)
+ {
+ continue;
+ }
+
+ {
+ //转译的Entity类名
+ var entityName = string.Empty;
+ var eType = (attributeSyntax.ArgumentList!.Arguments[0].Expression as TypeOfExpressionSyntax)!.Type;
+ if (eType.IsKind(SyntaxKind.IdentifierName))
+ {
+ entityName = (eType as IdentifierNameSyntax)!.Identifier.ValueText;
+ }
+ else if (eType.IsKind(SyntaxKind.QualifiedName))
+ {
+ entityName = (eType as QualifiedNameSyntax)!.ToString().Split(['.']).Last();
+ }
+ else if (eType.IsKind(SyntaxKind.AliasQualifiedName))
+ {
+ entityName = (eType as AliasQualifiedNameSyntax)!.ToString().Split(['.']).Last();
+ }
+ if (string.IsNullOrEmpty(entityName))
+ {
+ continue;
+ }
+ //排除的属性
+ List Excapes = [];
+ for (var i = 1; i < attributeSyntax.ArgumentList.Arguments.Count; i++)
+ {
+ var expressionSyntax = attributeSyntax.ArgumentList.Arguments[i].Expression;
+ if (expressionSyntax.IsKind(SyntaxKind.InvocationExpression))
+ {
+ var name = (expressionSyntax as InvocationExpressionSyntax)!.ArgumentList.DescendantNodes().First().ToString();
+ Excapes.Add(name.Split(['.']).Last());
+ }
+ else if ((expressionSyntax.IsKind(SyntaxKind.StringLiteralExpression)))
+ {
+ var name = (expressionSyntax as LiteralExpressionSyntax)!.Token.ValueText;
+ Excapes.Add(name);
+ }
+ }
+
+ var className = node.Identifier.ValueText;
+ var rootNamespace = node.AncestorsAndSelf().OfType().Single().Name.ToString();
+
+ StringBuilder bodyBuilder = new();
+ List namespaces = [];
+ StringBuilder bodyInnerBuilder = new();
+
+ //生成属性
+ void genProperty(TypeSyntax @type)
+ {
+ var symbols = compilation.GetSymbolsWithName(type.ToString());
+ foreach (ITypeSymbol symbol in symbols.Cast())
+ {
+ var fullNameSpace = symbol.ContainingNamespace.ToDisplayString();
+ //命名空间
+ if (!namespaces.Contains(fullNameSpace))
+ {
+ namespaces.Add(fullNameSpace);
+ }
+ symbol.GetMembers().OfType().ToList().ForEach(prop =>
+ {
+ if (!Excapes.Contains(prop.Name))
+ {
+ //prop:
+ var raw = $"public {prop.Type.ToDisplayString()} {prop.Name} {{get;set;}}";
+ //body:
+ bodyInnerBuilder.AppendLine($"/// ");
+ bodyInnerBuilder.AppendLine($"{raw}");
+ }
+ });
+ }
+ }
+
+ //生成属性:
+ var symbols = compilation.GetSymbolsWithName(entityName, SymbolFilter.Type);
+ var symbol = symbols.Cast().FirstOrDefault();
+ genProperty(SyntaxFactory.ParseTypeName(symbol.MetadataName));
+
+ //生成父类的属性:
+ INamedTypeSymbol? baseType = symbol.BaseType;
+ while (baseType != null)
+ {
+ genProperty(SyntaxFactory.ParseTypeName(baseType.MetadataName));
+ baseType = baseType.BaseType;
+ }
+
+ var rawClass = classTemp.Replace("$className", className);
+ rawClass = rawClass.Replace("$body", bodyInnerBuilder.ToString());
+ //append:
+ bodyBuilder.AppendLine(rawClass);
+
+ string rawNamespace = string.Empty;
+ namespaces.ToList().ForEach(ns => rawNamespace += $"using {ns};\r\n");
+
+ var source = sb.ToString();
+ source = source.Replace("$namespace", rawNamespace);
+ source = source.Replace("$classes", bodyBuilder.ToString());
+ source = source.Replace("$ni", rootNamespace);
+ //format:
+ source = FormatContent(source);
+ context.AddSource($"Biwen.AutoClassGenDto.{className}.{node.Identifier.Text}.g.cs", SourceText.From(source, Encoding.UTF8));
+ }
+ }
+ }
+
///
/// 格式化代码
///
diff --git a/Biwen.AutoClassGen.TestConsole/Dtos/UserDto.cs b/Biwen.AutoClassGen.TestConsole/Dtos/UserDto.cs
new file mode 100644
index 0000000..9f99b0a
--- /dev/null
+++ b/Biwen.AutoClassGen.TestConsole/Dtos/UserDto.cs
@@ -0,0 +1,17 @@
+using Biwen.AutoClassGen.TestConsole.Entitys;
+
+
+#pragma warning disable
+namespace Biwen.AutoClassGen.TestConsole.Dtos
+{
+
+ ///
+ /// to be generated
+ ///
+ [AutoDto(typeof(User), nameof(User.Id), "TestCol")]
+ public partial class UserDto
+ {
+
+ }
+}
+#pragma warning restore
\ No newline at end of file
diff --git a/Biwen.AutoClassGen.TestConsole/Entitys/User.cs b/Biwen.AutoClassGen.TestConsole/Entitys/User.cs
new file mode 100644
index 0000000..096b96c
--- /dev/null
+++ b/Biwen.AutoClassGen.TestConsole/Entitys/User.cs
@@ -0,0 +1,47 @@
+namespace Biwen.AutoClassGen.TestConsole.Entitys
+{
+ public class User : Info
+ {
+ ///
+ /// Id
+ ///
+ public string Id { get; set; } = null!;
+ ///
+ /// first name
+ ///
+ public string FirstName { get; set; } = null!;
+
+ ///
+ /// last name
+ ///
+ public string LastName { get; set; } = null!;
+
+ ///
+ /// age
+ ///
+ public int? Age { get; set; }
+
+ ///
+ /// fullname
+ ///
+ public string? FullName => $"{FirstName} {LastName}";
+
+ }
+
+ public abstract class Info : Other
+ {
+ ///
+ /// email
+ ///
+ public string? Email { get; set; }
+ }
+
+ public abstract class Other
+ {
+ ///
+ /// remark
+ ///
+ public string? Remark { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/Biwen.AutoClassGen.TestConsole/Program.cs b/Biwen.AutoClassGen.TestConsole/Program.cs
index d118115..3ca679f 100644
--- a/Biwen.AutoClassGen.TestConsole/Program.cs
+++ b/Biwen.AutoClassGen.TestConsole/Program.cs
@@ -11,7 +11,15 @@
KeyWord = "biwen"
};
-Console.WriteLine($"{queryRequest.KeyWord}");
+Biwen.AutoClassGen.TestConsole.Dtos.UserDto userDto = new()
+{
+ FirstName = "biwen",
+ LastName = "wan",
+ Age = 18,
+};
+Console.WriteLine($"{queryRequest.KeyWord}");
+Console.WriteLine($"I`m {userDto.FirstName} {userDto.LastName} I`m {userDto.Age} years old");
+
Console.ReadLine();
\ No newline at end of file