您现在的位置是:首页 >技术教程 >C#代码生成器网站首页技术教程

C#代码生成器

淘气的888 2025-05-15 00:01:03
简介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; }
    //}

}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。