您现在的位置是:首页 >技术教程 >C#代码生成器网站首页技术教程
C#代码生成器
简介C#代码生成器
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Reflection;
namespace ActionSourceGenerator
{
[Generator]
public class ActionSourceGenerator : ISourceGenerator
{
//定义参数生成特性
string attrSource = $@"using System;
namespace ActionSourceGenerator{{
[AttributeUsage(AttributeTargets.Field,Inherited = false, AllowMultiple = false)]
sealed class ActionParamAutoBuildAttribute : Attribute{{
public ActionParamAutoBuildAttribute(string bingdingMemberName = ""Text"",bool isBangding = true, string propertyName = """", Type propertyType = null,string defaultParam = """")
{{
BindMemberName = bingdingMemberName;
IsBangding = isBangding;
PropertyName = propertyName;
PropertyType = propertyType;
DefaultParam = defaultParam;
}}
public string PropertyName {{ get; set; }}
/// </summary>
///默认是Text
/// </summary>
public string BindMemberName {{ get; set; }}
public bool IsBangding {{ get; set; }}
public Type PropertyType {{ get; set; }}
/// </summary>
///参数的默认值,string类型为空,int类型为0,bool类型为false
/// </summary>
public string DefaultParam {{get;set;}}
}}
}}";
//定义action自动重写特性
string actionAttrSource = $@"
namespace ActionSourceGenerator{{
[AttributeUsage(AttributeTargets.Class,Inherited = false, AllowMultiple = false)]
sealed class ActionAutoOverrideAttribute : Attribute{{
public ActionAutoOverrideAttribute(Type uiClass){{
BandingUIClass = uiClass;
}}
public Type BandingUIClass {{ get; set; }}
}}
}}
";
/// <summary>
///
/// </summary>
/// <param name="context"></param>
public void Execute(GeneratorExecutionContext context)
{
if (!(context.SyntaxReceiver is ImpISyntaxReceiver syntaxReceiver))
{
return;
}
string source = attrSource + actionAttrSource;
//添加参数自动生成特性文本
context.AddSource("ActionAutoBuildAttribute.g.cs", SourceText.From(source, Encoding.UTF8));
CSharpParseOptions options = (context.Compilation as CSharpCompilation).SyntaxTrees[0].Options as CSharpParseOptions;
//添加特性的语法树到编译器
Compilation compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(source, options));
//添加扩展方法
#region 处理action自动重写 这两个分支可封装成对应方法
{
ITypeSymbol attrSymbol = compilation.GetTypeByMetadataName("ActionSourceGenerator.ActionAutoOverrideAttribute");
//获取Action基类
var baseUISymbol = context.Compilation.GetTypeByMetadataName("ManagementServer.TAction");
foreach (var typeDeclarationSyntax in syntaxReceiver.CandidateClasses)
{
var typeSymbol = compilation.GetSemanticModel(typeDeclarationSyntax.SyntaxTree).GetDeclaredSymbol(typeDeclarationSyntax) as ITypeSymbol;
if (typeSymbol.GetAttributes().Any(attr => attr.AttributeClass.Equals(attrSymbol, SymbolEqualityComparer.Default)))
{
//只对继承UI基类的类进行操作
//if (!typeSymbol.BaseType.(baseUISymbol, SymbolEqualityComparer.Default))
//{
// return;
//}
var attrData = typeSymbol.GetAttributes().Single(attr => attr.AttributeClass.Equals(attrSymbol, SymbolEqualityComparer.Default));
var typeOfUI = attrData.ConstructorArguments.Single().Value as ISymbol;
var typeName = typeOfUI.OriginalDefinition.MetadataName;
string overrideSource = $@"
using ManagementServer;
namespace {typeSymbol.ContainingNamespace.ToDisplayString()}{{
public partial class {typeSymbol.Name}{{
public override UC_BaseInput GetUserUI(){{
return new {typeName}(this);
}}
public override void SetData(string Json)
{{
{typeName}_AutoParam param = null;
//尝试创建一个对象Json
if (string.IsNullOrEmpty(Json))
{{
param = new {typeName}_AutoParam();
}}
else
{{
try
{{
param = DataDefined.TTools.MakeJsonObjec<{typeName}_AutoParam>(Json);
}}
catch
{{
param = new {typeName}_AutoParam();
}}
}}
//赋值给actionpara
if (param is null || !ActionPara.GetType().IsAssignableFrom(param.GetType()))
{{
return;
}}
foreach (var p1 in ActionPara.GetType().GetProperties())
{{var p2 = param.GetType().GetProperty(p1.Name);
if (p2 != null)
{{
p1.SetValue(ActionPara, p2.GetValue(param, null), null);
}}
}}
}}
public new {typeName}_AutoParam ActionPara
{{get
{{
if (_ActionPara == null)
{{
_ActionPara = new {typeName}_AutoParam();
_ActionPara.PropertyChanged += DoEventUserDataChanged;
}}
return ({typeName}_AutoParam)_ActionPara;
}}
}}
}}
}} ";
context.AddSource($"{typeSymbol.Name}.g.cs", SourceText.From(overrideSource, Encoding.UTF8));
}
}
}
#endregion
#region 处理参数自动生成 这两个分支可封装成对应方法
{
//获取特性符号
ITypeSymbol attrSymbol = compilation.GetTypeByMetadataName("ActionSourceGenerator.ActionParamAutoBuildAttribute");
List<IFieldSymbol> fieldSymbols = new List<IFieldSymbol>();
//取出拥有该特性的字段
//遍历字段声明的语法
foreach (FieldDeclarationSyntax fieldDeclarationSyntax in syntaxReceiver.CandidateFields)
{
//从该字段语法树上获取语义模型
SemanticModel semanticModel = compilation.GetSemanticModel(fieldDeclarationSyntax.SyntaxTree);
//遍历该字段语法上的变量声明符语法
foreach (VariableDeclaratorSyntax variable in fieldDeclarationSyntax.Declaration.Variables)
{
IFieldSymbol symbol = semanticModel.GetDeclaredSymbol(variable) as IFieldSymbol;
//是否有该特性
if (symbol.GetAttributes().Any(m => m.AttributeClass.Equals(attrSymbol, SymbolEqualityComparer.Default)))
{
fieldSymbols.Add(symbol);
}
}
}
//对拥有特性的字段符号进行分组,然后遍历
foreach (IGrouping<ISymbol, IFieldSymbol> group in fieldSymbols.GroupBy(m => m.ContainingType, SymbolEqualityComparer.Default))
{
var t = group.Key as INamedTypeSymbol;
ProcessClass(t, group.ToList(), context, attrSymbol);
}
}
#endregion
}
/// <summary>
/// 处理分组,分别生成对应的代码
/// </summary>
/// <param name="typeSymbol"></param>
/// <param name="fieldSymbols"></param>
/// <param name="context"></param>
void ProcessClass(INamedTypeSymbol typeSymbol, List<IFieldSymbol> fieldSymbols, GeneratorExecutionContext context, ISymbol attributeSymbol)
{
//类被包含符号与被包含的命名空间比对
if (!typeSymbol.ContainingSymbol.Equals(typeSymbol.ContainingNamespace, SymbolEqualityComparer.Default))
{
return;
}
//获取UI基类
var baseUISymbol = context.Compilation.GetTypeByMetadataName("ManagementServer.UC_BaseInput");
//只对继承UI基类的类进行操作
if (!typeSymbol.BaseType.Equals(baseUISymbol, SymbolEqualityComparer.Default))
{
return;
}
//获取命名空间
string namespaceName = typeSymbol.ContainingNamespace.ToDisplayString();
//获取参数接口符号
var baseParaSymbol = context.Compilation.GetTypeByMetadataName("DataDefined.TBasePara");
// 开始构建要⽣成的代码
//生成para类
StringBuilder source = new StringBuilder($@"
using DataDefined;
using System.Runtime.Serialization;
using System;
using System.Text;
namespace {namespaceName} {{
[DataContract]
public partial class {typeSymbol.Name}_AutoParam : {baseParaSymbol.ToDisplayString()} {{ ");
//根据UI类字段生成para类的对应字段及属性
foreach (var field in fieldSymbols)
{
ProcessField(source, field, attributeSymbol);
}
//tostring方法
string apd = $"stringBuilder.Append($@"{{ p.Name}}:{{ p.GetValue(this)?.ToString()}}; ");";
source.AppendLine($@"public override string ToString()
{{
StringBuilder stringBuilder = new StringBuilder();
foreach (var p in GetType().GetProperties()) {{
{apd}
}}
return stringBuilder.ToString();
}}");
source.Append("} }");
context.AddSource($"{typeSymbol.Name}_AutoParam.cs", SourceText.From(source.ToString(), Encoding.UTF8));
//对该类添加绑定扩展
StringBuilder bindingSource = new StringBuilder($@"
using System.Windows.Forms;
namespace {namespaceName} {{
public partial class {typeSymbol.Name} {{ ");
bindingSource.Append("
void InitBindPara(dynamic act) {");
foreach (var field in fieldSymbols)
{
ProcessFieldForBinding(bindingSource, field, attributeSymbol);
}
bindingSource.Append("}");
bindingSource.Append("} }");
context.AddSource($"{typeSymbol.Name}.g.cs", SourceText.From(bindingSource.ToString(), Encoding.UTF8));
}
/// <summary>
/// 生成param类的字段和属性
/// </summary>
/// <param name="source"></param>
/// <param name="fieldSymbol"></param>
/// <param name="attributeSymbol"></param>
private void ProcessField(StringBuilder source, IFieldSymbol fieldSymbol, ISymbol attributeSymbol)
{
AttributeData attributeData = fieldSymbol.GetAttributes().Single(ad => ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.Default));
TypedConstant overridenNameOpt = attributeData.ConstructorArguments[2];
var bindmember = attributeData.ConstructorArguments[0].Value.ToString();
var propertyType = attributeData.ConstructorArguments[3].Value?.ToString();
var defaultParam = attributeData.ConstructorArguments[4].Value.ToString();
var typeName = string.IsNullOrEmpty(propertyType) ? ChooseType(bindmember, fieldSymbol) : propertyType;
var currentParam = string.IsNullOrWhiteSpace(defaultParam) ? GetDefaultParam(typeName) : defaultParam;
string fieldName;
string propertyName = chooseName(out fieldName, overridenNameOpt);
if (propertyName.Length == 0 || propertyName == fieldName)
{
return;
}
source.Append($@"
private {typeName} {fieldName}={currentParam};");
source.Append($@"
[DataMember]
public {typeName} {propertyName}
{{
get
{{
return this.{fieldName};
}}
set
{{
this.{fieldName} = value;
}}
}}
");
}
string ChooseType(string bindingMember, IFieldSymbol fieldSymbol)
{
var typeSymbol = fieldSymbol.Type.OriginalDefinition;
var memberSymbol = typeSymbol.GetMembers(bindingMember).FirstOrDefault();
if (memberSymbol == null)
{
switch (bindingMember.Trim().ToLower())
{
case "text":
return "string";
case "checked":
return "bool";
default:
return "object";
}
}
else
{
return (memberSymbol as IPropertySymbol).Type.OriginalDefinition.Name;
}
}
string GetDefaultParam(string type)
{
switch(type)
{
case "string":
return """";
case "bool":
return "false";
case "int":
return "0";
case "double":
return "0";
default:
return "0";
}
}
string chooseName(out string fieldName, TypedConstant overridenNameOpt)
{
if (overridenNameOpt.IsNull)
{
fieldName = "";
return "";
}
string str = overridenNameOpt.Value.ToString();
fieldName = str.ToLower().Insert(0, "_");
return str;
}
private void ProcessFieldForBinding(StringBuilder source, IFieldSymbol fieldSymbol, ISymbol attributeSymbol)
{
获取该字段符号的特性
AttributeData attrData = fieldSymbol.GetAttributes().Single(attr => attr.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.Default));
var bindmember = attrData.ConstructorArguments[0].Value.ToString();
TypedConstant overridenNameOpt = attrData.ConstructorArguments[2];
source.Append($"
{fieldSymbol.Name}.DataBindings.Add(new Binding("{bindmember}", act.ActionPara, "{overridenNameOpt.Value.ToString()}", false, DataSourceUpdateMode.OnPropertyChanged));
");
}
public void Initialize(GeneratorInitializationContext context)
{
// Debugger.Launch();
//注册一个语法的通知类型,作用是运行源代码生成器的时候,去检查固定语法是否满足条件
context.RegisterForSyntaxNotifications(() => new ImpISyntaxReceiver());
}
}
/// <summary>
/// 语法接收器
/// </summary>
class ImpISyntaxReceiver : ISyntaxReceiver
{
/// <summary>
/// 存储候选字段
/// </summary>
public List<FieldDeclarationSyntax> CandidateFields { get; } = new List<FieldDeclarationSyntax>();
/// <summary>
/// 存储候选类
/// </summary>
public List<ClassDeclarationSyntax> CandidateClasses { get; } = new List<ClassDeclarationSyntax>();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is FieldDeclarationSyntax fieldDeclarationSyntax && fieldDeclarationSyntax.AttributeLists.Count > 0)
{
CandidateFields.Add(fieldDeclarationSyntax);
}
if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax && classDeclarationSyntax.AttributeLists.Count > 0)
{
CandidateClasses.Add(classDeclarationSyntax);
}
}
}
//[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
//sealed class ActionParamAutoBuildAttribute : Attribute
//{
// public ActionParamAutoBuildAttribute(string bingdingMemberName = "Text", bool isBangding = true, string propertyName = "")
// {
// BindMemberName = bingdingMemberName;
// IsBangding = isBangding;
// PropertyName = propertyName;
// }
// public string PropertyName { get; set; }
// ///<summer>
// ///默认是Text
// ///</summary>
// public string BindMemberName { get; set; }
// public bool IsBangding { get; set; }
//}
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。