C#后端之CodeDom在内存中创建对象最简明的讲解(下)附源码Net5和NetCore可用

嗯,这里就是最后一章了,至于为什么是红字,就是为了和前面假装同意一点,啊哈哈哈

 

先上源码,900多行,我折叠了,具体怎么用看后面讲解。

 

    public class CodeMake
    {
        #region Field Area
        private CodeNamespace _samples;
        private CodeCompileUnit _targetUnit;
        private CodeTypeDeclaration _targetClass;
        private readonly string _outputFileName;
        private static IList<string> _assemblyUsingLocation = null;
        private event Action _assemblyLoad = null;
        /// <summary>
        /// 单例IOC容器
        /// </summary>
        private static Dictionary<string, object> _singletonContainer = null;
        private static readonly object _lock_obj = new object();

        /// <summary>
        /// 命名空间
        /// </summary>
        public string NameSpace { get; private set; }
        /// <summary>
        /// 类名称
        /// </summary>
        public string ClassName { get; private set; }
        /// <summary>
        /// 命名空间+类名称
        /// </summary>
        public string FullNameSpaceWithClass { get; private set; }

        #region CodeMaker Filter 节点
        private static bool _onecEventNotRun = true;
        /// <summary>
        /// 整个项目运行中只调用一次的事件,事件发生点在尚未构造对象之前
        /// </summary>
        public event Action DoOnceWorkBeforeConstructor = null;

        /// <summary>
        /// 开始构造函数之前
        /// </summary>
        public event Action BeforeConstructor = null;
        /// <summary>
        /// 结束构造函数时
        /// </summary>
        public event Action AfterConstructor = null;

        /// <summary>
        /// 添加命名空间之前(生成代码 AddNamespace)
        /// </summary>
        public event Action BeforeAddNamespace = null;
        /// <summary>
        /// 添加命名空间之后(生成代码 AddNamespace)
        /// </summary>
        public event Action AfterAddNamespace = null;

        /// <summary>
        /// 添加构造函数之前(生成代码 AddConstructor)
        /// </summary>
        public event Action BeforeAddConstructor = null;
        /// <summary>
        /// 添加构造函数之后(生成代码 AddConstructor)
        /// </summary>
        public event Action AfterAddConstructor = null;

        /// <summary>
        /// 添加字段之前(生成代码 AddField)
        /// </summary>
        public event Action BeforeAddField = null;
        /// <summary>
        /// 添加字段之后(生成代码 AddField)
        /// </summary>
        public event Action AfterAddField = null;

        /// <summary>
        /// 添加属性之前(生成代码 AddPropertie)
        /// </summary>
        public event Action BeforeAddPropertie = null;
        /// <summary>
        /// 添加属性之后(生成代码 AddPropertie)
        /// </summary>
        public event Action AfterAddPropertie = null;

        /// <summary>
        /// 添加方法之前(生成代码 AddMethod)
        /// </summary>
        public event Action BeforeAddMethod = null;
        /// <summary>
        /// 添加方法之后(生成代码 AddMethod)
        /// </summary>
        public event Action AfterAddMethod = null;

        /// <summary>
        /// 创建对象之前(生成实例 CreateInstance)
        /// </summary>
        public event Action BeforeCreateInstance = null;
        /// <summary>
        /// 创建对象之后(生成实例 CreateInstance)
        /// </summary>
        public event Action AfterCreateInstance = null;

        #endregion

        #endregion

        #region Ctor
        static CodeMake()
        {
            if (_singletonContainer is null)
            {
                lock (_lock_obj)
                {
                    if (_singletonContainer is null)
                    {
                        _singletonContainer = new Dictionary<string, object>();
                    }
                }
            }
            if (_assemblyUsingLocation is null)
            {
                lock (_lock_obj)
                {
                    if (_assemblyUsingLocation is null)
                    {
                        _assemblyUsingLocation = new List<string>();
                    }
                }
            }
        }

        public CodeMake(bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
            : this("CodeDOM", reLoadAssembly, eventCallBack)
        {
        }
        public CodeMake(string nameSpace, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
            : this(nameSpace, "System", reLoadAssembly, eventCallBack)
        {
        }
        public CodeMake(string nameSpace, string usingNameSpace, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
            : this(nameSpace, usingNameSpace, "CreatedClass", reLoadAssembly, eventCallBack)
        {

        }

        public CodeMake(string nameSpace, string usingNameSpace, string className, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
            : this(nameSpace, usingNameSpace, className, TypeAttributes.Public, reLoadAssembly, eventCallBack)
        {

        }
        public CodeMake(string nameSpace, string usingNameSpace, string className, TypeAttributes visitAttr, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
            : this(nameSpace, usingNameSpace, className, visitAttr, "C:\\", reLoadAssembly, eventCallBack)
        {

        }
        public CodeMake(string nameSpace, string usingNameSpace, string className, TypeAttributes visitAttr, string fileFullPath, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
        {
            #region Verify Area
            if (string.IsNullOrEmpty(nameSpace))
            {
                throw new ArgumentException("命名空间不能为空");
            }
            if (string.IsNullOrEmpty(className))
            {
                throw new ArgumentException("类名不能为空");
            }
            #endregion

            if (eventCallBack != null)
            {
                eventCallBack(this);
            }
            if (_onecEventNotRun)
            {
                if (DoOnceWorkBeforeConstructor != null)
                {
                    DoOnceWorkBeforeConstructor();
                    _onecEventNotRun = false;
                }
            }

            if (BeforeConstructor != null)
            {
                BeforeConstructor();
            }

            #region Main
            if (_assemblyUsingLocation.Count <= 0)
            {
                _assemblyLoad += () => LoadBasicAssembly();
            }
            if (reLoadAssembly)
            {
                _assemblyLoad += () => LoadBasicAssembly();
            }

            _targetUnit = new CodeCompileUnit();
            _samples = new CodeNamespace(nameSpace);
            _samples.Imports.Add(new CodeNamespaceImport(usingNameSpace));
            _targetClass = new CodeTypeDeclaration(className);
            _targetClass.IsClass = true;
            _targetClass.TypeAttributes = visitAttr;
            _samples.Types.Add(_targetClass);
            _targetUnit.Namespaces.Add(_samples);

            NameSpace = nameSpace;
            ClassName = className;
            FullNameSpaceWithClass = NameSpace + "." + ClassName;

            _outputFileName = fileFullPath;
            #endregion

            if (AfterConstructor != null)
            {
                AfterConstructor();
            }
        }

        #endregion

        #region AssemblyLoadLocation Function Area
        /// <summary>
        /// 基础程序集加载
        /// </summary>
        private void LoadBasicAssembly()
        {
            if (_assemblyUsingLocation.Count > 0)
            {
                _assemblyUsingLocation.Clear();
            }
            DirectoryInfo root1 = new DirectoryInfo(AppContext.BaseDirectory);
            foreach (FileInfo f in root1.GetFiles())
            {
                if (f.Name.Contains(".dll", StringComparison.OrdinalIgnoreCase))
                {
                    AddedAssemblyBy(f.FullName);
                }
            }
            AddedAssemblyBy(typeof(System.Object).GetTypeInfo().Assembly.Location);
            AddedAssemblyBy(typeof(Console).GetTypeInfo().Assembly.Location);
            AddedAssemblyBy(Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll"));
        }

        /// <summary>
        /// 加载程序集
        /// </summary>
        /// <param name="location"></param>
        private void AddedAssemblyBy(string location)
        {
            if (!_assemblyUsingLocation.Any(s => s.Contains(location)))
            {
                _assemblyUsingLocation.Add(location);
            }
        }

        /// <summary>
        /// 自定义一个生成对象引用的程序集扩展
        /// </summary>
        /// <param name="assemblyLocations"></param>
        /// <returns></returns>
        public CodeMake AddAssembly(string assemblyLocation)
            => AddAssemblys(new List<string> { assemblyLocation });

        /// <summary>
        /// 自定义一组生成对象引用的程序集扩展
        /// </summary>
        /// <param name="assemblyLocations"></param>
        /// <returns></returns>
        public CodeMake AddAssemblys(List<string> assemblyLocations)
        {
            foreach (var location in assemblyLocations)
            {
                _assemblyLoad += () => AddedAssemblyBy(location);
            }
            return this;
        }
        #endregion

        #region NameSpaceAdded Function Area

        /// <summary>
        /// 新增命名空间
        /// </summary>
        /// <param name="codeNamespaceImport">命名空间文本,不需要添加using</param>
        public CodeMake AddNamespace(string codeNamespaceImport)
            => AddNamespaces(() => new List<CodeNamespaceImport> { new CodeNamespaceImport(codeNamespaceImport) });

        /// <summary>
        /// 新增多个命名空间
        /// </summary>
        /// <param name="codeNamespaceImport">命名空间文本,不需要添加using</param>
        public CodeMake AddNamespaces(List<string> codeNamespaceImport)
        {
            List<CodeNamespaceImport> codeNamespace = new List<CodeNamespaceImport>();
            codeNamespaceImport.ForEach(c => codeNamespace.Add(new CodeNamespaceImport(c)));
            return AddNamespaces(() => codeNamespace);
        }

        /// <summary>
        /// 新增命名空间 自定义
        /// 
        ///     Demo
        ///     var codeNamespace = new CodeNamespaceImport>("namespace");
        /// </summary>
        /// <param name="codeNamespaceImport"></param>
        public CodeMake AddNamespace(Func<CodeNamespaceImport> codeNamespaceImport)
            => AddNamespaces(() => new List<CodeNamespaceImport> { codeNamespaceImport() });

        /// <summary>
        /// 新增命名空间 自定义
        /// 
        ///     Demo
        ///     var codeNamespace = new List<CodeNamespaceImport>()
        ///     {
        ///         new CodeNamespaceImport("namespace")
        ///     };
        /// </summary>
        /// <param name="codeNamespaceImport"></param>
        public CodeMake AddNamespaces(Func<List<CodeNamespaceImport>> codeNamespaceImport)
        {
            if (BeforeAddNamespace != null)
            {
                BeforeAddNamespace();
            }
            codeNamespaceImport().ForEach(c => _samples.Imports.Add(c));
            if (AfterAddNamespace != null)
            {
                AfterAddNamespace();
            }
            return this;
        }
        #endregion

        #region Inherit Function Area

        /// <summary>
        /// 继承接口名称
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public CodeMake AddInherit(string name)
        {
            _targetClass.BaseTypes.Add(name);
            return this;
        }

        /// <summary>
        /// 继承接口类型
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public CodeMake AddInherit(Type name)
        {
            _targetClass.BaseTypes.Add(name);
            return this;
        }
        #endregion

        #region Constructor Function Area

        /// <summary>
        /// 添加构造函数
        /// </summary>
        /// <param name="ctor">ctor</param>
        public CodeMake AddConstructor(ConstructorEntity ctor)
         => AddConstructor(() =>
            {
                if (ctor is null)
                {
                    throw new ArgumentException("构造函数基本访问类型参数不能为空");
                }
                // Declare the constructor
                CodeConstructor constructor = new CodeConstructor();
                constructor.Attributes = ctor.Attr;
                if (ctor.Params != null)
                {
                    ctor.Params.ForEach(s =>
                    {
                        // Add parameters.
                        constructor.Parameters.Add(new CodeParameterDeclarationExpression(
                            s.ParamType, s.Name));

                        if (!string.IsNullOrEmpty(s.ReferenceName))
                        {
                            // Add field initialization logic
                            CodeFieldReferenceExpression reference =
                                new CodeFieldReferenceExpression(
                                new CodeThisReferenceExpression(), s.ReferenceName);

                            constructor.Statements.Add(new CodeAssignStatement(reference,
                                new CodeArgumentReferenceExpression(s.Name)));
                        }

                    });
                }
                return constructor;
            });

        /// <summary>
        /// 添加构造函数
        /// </summary>
        /// <param name="ctor">ctor</param>
        public CodeMake AddConstructor(Func<CodeConstructor> ctor)
        {
            if (BeforeAddConstructor != null)
            {
                BeforeAddConstructor();
            }

            _targetClass.Members.Add(ctor());

            if (AfterAddConstructor != null)
            {
                AfterAddConstructor();
            }
            return this;
        }

        #endregion

        #region Field Function Area

        /// <summary>
        /// 新增字段
        /// </summary>
        /// <param name="FieldEntity">字段Model</param>
        public CodeMake AddField(FieldEntity fieldModel)
            => AddField(() =>
            {
                if (fieldModel is null)
                {
                    throw new ArgumentException("字段参数信息不能为null");
                }
                return GetFieldBy(fieldModel);
            });

        /// <summary>
        /// 新增多个字段
        /// </summary>
        /// <param name="FieldEntity">字段Model</param>
        public CodeMake AddFields(List<FieldEntity> fields)
        {
            fields.ForEach(f => AddField(f));
            return this;
        }

        /// <summary>
        /// 新增字段
        /// </summary>
        /// <param name="attr">字段标签</param>
        /// <param name="fieldName">字段名称</param>
        /// <param name="fieldType">字段类型</param>
        /// <param name="comment">字段注释</param>
        public CodeMake AddField(string fieldName, Type fieldType, MemberAttributes attr = MemberAttributes.Public , object defaultValue = default, string comment = null)
            => AddField(
                new FieldEntity(fieldName, fieldType)
                {
                    Attr = attr,
                    Comment = comment,
                    DefaultValue = defaultValue,
                });

        /// <summary>
        /// 新增字段(自定义)
        /// 
        /// 示例:
        ///         CodeMemberField field = new CodeMemberField();
        ///         field.Attributes = attr;
        ///         field.Name = fieldName;
        ///         field.Type = new CodeTypeReference(fieldType);
        ///         if (!string.IsNullOrEmpty(comment))
        ///         {
        ///             field.Comments.Add(new CodeCommentStatement(comment));
        ///         }
        ///         return field;
        /// </summary>
        /// <param name="fieldMember">字段类型</param>
        public CodeMake AddField(Func<CodeMemberField> fieldMember)
            => AddFields(() => new List<CodeMemberField> { fieldMember() });

        /// <summary>
        /// 新增多个字段(自定义)
        /// 
        /// 
        ///         Demo:
        ///         List<CodeMemberField> fields = new List<CodeMemberField>();
        ///         CodeMemberField field = new CodeMemberField();
        ///         field.Attributes = attr;
        ///         field.Name = fieldName;
        ///         field.Type = new CodeTypeReference(fieldType);
        ///         if (!string.IsNullOrEmpty(comment))
        ///         {
        ///             field.Comments.Add(new CodeCommentStatement(comment));
        ///         }
        ///         fields.Add(field);
        ///         return fields;
        ///         
        /// </summary>
        /// <param name="fieldMember"></param>
        public CodeMake AddFields(Func<List<CodeMemberField>> fieldMember)
        {
            if (BeforeAddField != null)
            {
                BeforeAddField();
            }
            fieldMember().ForEach(f => _targetClass.Members.Add(f));
            if (AfterAddField != null)
            {
                AfterAddField();
            }
            return this;
        }

        private CodeMemberField GetFieldBy(FieldEntity fieldModel)
        {
            // Declare the Value field.
            CodeMemberField field = new CodeMemberField(new CodeTypeReference(fieldModel.Type), fieldModel.Name);
            field.Attributes = fieldModel.Attr;
            if (fieldModel.DefaultValue != null)
            {
                field.InitExpression = new CodePrimitiveExpression(fieldModel.DefaultValue);
            }
            if (!string.IsNullOrEmpty(fieldModel.Comment))
            {
                field.Comments.Add(new CodeCommentStatement(fieldModel.Comment));
            }
            return field;
        }
        #endregion

        #region Properties Function Area

        /// <summary>
        /// 新增属性
        /// </summary>
        /// <param name="pro">属性Model</param>
        public CodeMake AddPropertie(PropertyEntity pro)
            => AddProperties(() =>
            {
                if (pro is null)
                {
                    throw new ArgumentException("属性参数信息不能为null");
                }


                // Declare the read-only Width property.
                string fieldName = string.Empty;
                if (pro.HasGet && pro.HasSet)
                {
                    fieldName = pro.Name + " { get; set; }//";
                }
                else if (pro.HasGet && !pro.HasSet)
                {
                    fieldName = pro.Name + " { get; }//";
                }
                else
                {
                    throw new ArgumentException("属性不能设置只写或当成字段来使用");
                }

                var propertity = GetFieldBy(new FieldEntity(fieldName, pro.Type)
                {
                    Attr = pro.Attr,
                    Comment = pro.Comment
                });
                return new List<CodeTypeMember> { propertity };
            });


        /// <summary>
        /// 增加属性
        /// </summary>
        /// <param name="attr">属性标签</param>
        /// <param name="propertieName">属性名称</param>
        /// <param name="propertieType">属性类型</param>
        /// <param name="comment">属性注释</param>
        public CodeMake AddPropertie(MemberAttributes attr, string propertieName, Type propertieType, string comment = null)
            => AddPropertie(new PropertyEntity(propertieName, propertieType)
            {
                HasGet = true,
                HasSet = true,
                Comment = comment
            });

        /// <summary>
        /// 添加多个属性
        /// </summary>
        /// <param name="pros"></param>
        public CodeMake AddProperties(List<PropertyEntity> pros)
        {
            pros.ForEach(s => AddPropertie(s));
            return this;
        }

        /// <summary>
        /// 新增1个属性(自定义)
        /// </summary>
        /// <param name="propertyMember">Func CodeTypeMember</param>
        public CodeMake AddPropertie(Func<CodeTypeMember> propertyMember)
            => AddProperties(() => new List<CodeTypeMember>
                {
                    propertyMember()
                }
            );

        /// <summary>
        /// 新增多个属性(自定义)
        /// </summary>
        /// <param name="propertyMember">Func list CodeTypeMember</param>
        public CodeMake AddProperties(Func<List<CodeTypeMember>> propertyMember)
        {
            if (BeforeAddPropertie != null)
            {
                BeforeAddPropertie();
            }

            propertyMember().ForEach(p => _targetClass.Members.Add(p));

            if (AfterAddPropertie != null)
            {
                AfterAddPropertie();
            }
            return this;
        }

        #endregion

        #region Method Area

        /// <summary>
        /// 添加方法
        /// </summary>
        /// <param name="methods">方法</param>
        /// <returns>this</returns>
        public CodeMake AddMethod(string method, string comment = null)
            => AddMethod(new MethodEntity { Method = method, Comment = comment });

        /// <summary>
        /// 添加单个方法
        /// </summary>
        /// <param name="methods">方法</param>
        /// <returns>this</returns>
        public CodeMake AddMethod(MethodEntity method)
            => AddMethods(new List<MethodEntity> { method });

        /// <summary>
        /// 添加多个方法
        /// </summary>
        /// <param name="methods">方法集合</param>
        /// <returns>this</returns>
        public CodeMake AddMethods(List<MethodEntity> methods)
            => AddMethods(() =>
            {
                var methodsList = new List<CodeTypeMember>();
                methods.ForEach(m =>
                {
                    CodeSnippetTypeMember snippet = new CodeSnippetTypeMember
                    {
                        Text = m.Method
                    };
                    if (!string.IsNullOrEmpty(m.Comment))
                    {
                        snippet.Comments.Add(new CodeCommentStatement(m.Comment, false));
                    }
                    methodsList.Add(snippet);
                });
                return methodsList;
            });


        /// <summary>
        /// 添加方法(自定义)
        /// </summary>
        /// <param name="method">Func<CodeTypeMember></param>
        public CodeMake AddMethod(Func<CodeTypeMember> method)
            => AddMethods(() => new List<CodeTypeMember> { method() });

        /// <summary>
        /// 添加多个方法(自定义)
        /// </summary>
        /// <param name="method">Func<List<CodeTypeMember>></param>
        public CodeMake AddMethods(Func<List<CodeTypeMember>> method)
        {
            if (BeforeAddMethod != null)
            {
                BeforeAddMethod();
            }

            method().ForEach(m => _targetClass.Members.Add(m));

            if (AfterAddMethod != null)
            {
                AfterAddMethod();
            }
            return this;
        }

        #endregion

        #region OutPut
        /// <summary>
        /// 控制台输出
        /// </summary>
        /// <returns></returns>
        public CodeMake Log()
        {
            Console.WriteLine(GenerateCSharpString());
            return this;
        }

        /// <summary>
        /// 元数据引用控制台输出
        /// </summary>
        /// <returns></returns>
        public CodeMake MetadataLog()
        {
            foreach (var item in _assemblyUsingLocation)
            {
                Console.WriteLine(item);
            }
            return this;
        }

        /// <summary>
        /// 文本输出(string)
        /// </summary>
        /// <param name="fileFullPath">文件地址</param>
        public string GenerateCSharpString()
            => CodeDomOutString(() =>
            {
                CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
                CodeGeneratorOptions options = new CodeGeneratorOptions { BracingStyle = "C" };

                using (StringWriter sourceWriter = new StringWriter())
                {
                    provider.GenerateCodeFromCompileUnit(_targetUnit, sourceWriter, options);
                    return sourceWriter.ToString();
                }
            });

        /// <summary>
        /// 自定义CodeDom输出(string)
        /// </summary>
        /// <param name="fileFullPath">文件地址</param>
        public string CodeDomOutString(Func<string> codeDomContext)
            => codeDomContext();


        /// <summary>
        /// 文件输出(.cs)
        /// </summary>
        /// <param name="fileFullPath">文件地址</param>
        public CodeMake GenerateCSharpFile(string fileFullPath)
        {
            if (string.IsNullOrEmpty(fileFullPath))
            {
                throw new ArgumentException("文件输出路径为空,请设置输出路径!");
            }
            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
            CodeGeneratorOptions options = new CodeGeneratorOptions();
            options.BracingStyle = "C";
            using (StreamWriter sourceWriter = new StreamWriter(fileFullPath))
            {
                provider.GenerateCodeFromCompileUnit(
                    _targetUnit, sourceWriter, options);
            }
            return this;
        }

        /// <summary>
        /// 文件输出(.cs)
        /// </summary>
        public CodeMake CodeDomOutFile()
            => GenerateCSharpFile(_outputFileName);
        #endregion

        #region CreateInstance Function Area

        /// <summary>
        /// 创建单例对象 默认获取方式为命名空间+类名
        /// </summary>
        /// <returns></returns>
        public object CreateInstanceOfSingleton()
            => CreateInstanceOfSingleton(this.GenerateCSharpString(), this.FullNameSpaceWithClass);

        /// <summary>
        /// 创建单例对象 存取Key自定义
        /// </summary>
        /// <param name="singletonKey"></param>
        /// <returns></returns>
        public object CreateInstanceOfSingleton(string singletonKey)
            => CreateInstanceOfSingleton(this.GenerateCSharpString(), singletonKey);

        /// <summary>
        /// 创建单例对象  按命名空间+类名区分
        /// </summary>
        /// <param name="context">创建对象文本</param>
        /// <param name="singletonKey">命名空间+类名称</param>
        /// <returns></returns>
        public object CreateInstanceOfSingleton(string context, string singletonKey)
        {
            if (HasSingletonInstance(singletonKey))
            {
                return GetSingletonInstanceBy(singletonKey);
            }
            var instance = CreateInstance(context, this.FullNameSpaceWithClass);
            _singletonContainer.Add(singletonKey, instance);
            return instance;
        }

        /// <summary>
        /// 根据本类构建对象
        /// </summary>
        /// <returns>返回Object类,根据内容反射获取信息</returns>
        public object CreateInstance()
            => CreateInstance(this.GenerateCSharpString(), this.FullNameSpaceWithClass);

        /// <summary>
        /// 根据传入内容构建对象
        /// </summary>
        /// <returns>返回Object类,根据内容反射获取信息</returns>
        public object CreateInstance(string context, string fullNamespaceClass)
            => CreateInstance(() =>
            {
                #region Verify
                if (string.IsNullOrEmpty(context))
                {
                    throw new ArgumentException("生成的代码不能为空");
                }
                if (string.IsNullOrEmpty(fullNamespaceClass))
                {
                    throw new ArgumentException("命名空间和类名称不能为空");
                }
                #endregion

                #region 加载构建
                //元数据加载
                if (_assemblyLoad != null)
                {
                    _assemblyLoad();
                }
                MetadataReference[] references = _assemblyUsingLocation.ToArray().Select(r => MetadataReference.CreateFromFile(r)).ToArray();


                CSharpCompilation compilation = CSharpCompilation.Create(
                    Path.GetRandomFileName(),
                    syntaxTrees: new[] { CSharpSyntaxTree.ParseText(context) },
                    references: references,
                    options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
                #endregion

                #region 创建对象
                using (var ms = new MemoryStream())
                {
                    EmitResult result = compilation.Emit(ms);

                    if (result.Success)
                    {
                        ms.Seek(0, SeekOrigin.Begin);

                        Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
                        //var type = assembly.GetType("CodeDOM.CodeDOMCreatedClass");
                        return assembly.CreateInstance(fullNamespaceClass);
                    }
                    else
                    {
                        return result.Diagnostics.Where(diagnostic =>
                                                    diagnostic.IsWarningAsError ||
                                                    diagnostic.Severity == DiagnosticSeverity.Error);
                    }
                }
                #endregion
            });

        /// <summary>
        /// 构建自定义生成方式和对象
        /// </summary>
        /// <returns>返回Object类,根据内容反射获取信息</returns>
        public object CreateInstance(Func<object> createInfo)
        {
            if (BeforeCreateInstance != null)
            {
                BeforeCreateInstance();
            }

            var resultObj = createInfo();

            if (AfterCreateInstance != null)
            {
                AfterCreateInstance();
            }

            return resultObj;
        }

        #endregion

        #region Singleton Ioc Function Area

        /// <summary>
        /// 获取单例对象
        /// </summary>
        /// <param name="key">命名空间+类名称</param>
        /// <returns></returns>
        public static object GetSingletonInstanceBy(string key)
            => HasSingletonInstance(key) ? _singletonContainer[key] : null;

        /// <summary>
        /// 是否包含单例对象
        /// </summary>
        /// <param name="key">命名空间+类名称</param>
        /// <returns></returns>
        public static bool HasSingletonInstance(string key)
            => _singletonContainer.ContainsKey(key);

        #endregion

    }
CodeMaker

 

 

 

咱们开发,碰到不知道的类一般怎么办,那肯定是先 new一个,再看看参数再说,然后连蒙带猜的写。

所以,我们说一些私有字段 然后讲构造函数。

使用起来大多数人都是 

CodeMacker code = new CodeMacker();

传参数,传啥参数,我哪儿知道。

     private CodeNamespace _samples;
        private CodeCompileUnit _targetUnit;
        private CodeTypeDeclaration _targetClass;
        private readonly string _outputFileName;

        /// <summary>
        /// 命名空间
        /// </summary>
        public string NameSpace { get; private set; }
        /// <summary>
        /// 类名称
        /// </summary>
        public string ClassName { get; private set; }
        /// <summary>
        /// 命名空间+类名称
        /// </summary>
        public string FullNameSpaceWithClass { get; private set; }

这几个是基本需要的参数,干嘛的就看名称猜吧,具体实现讲起来太累,看官网文档好点。

如果看了上面源码的就会发现少了点东西,没有了 一个字典和一堆Event,那个等会再说。

 

然后我们看构造函数

#region Ctor

        public CodeMacker(Action<CodeMacker> eventCallBack = null)
            : this("CodeDOM", eventCallBack)
        {
        }
        public CodeMacker(string nameSpace,Action<CodeMacker> eventCallBack = null)
            : this(nameSpace, "System", eventCallBack)
        {
        }
        public CodeMacker(string nameSpace, string usingNameSpace, Action<CodeMacker> eventCallBack = null)
            : this(nameSpace, usingNameSpace, "CreatedClass", eventCallBack)
        {

        }

        public CodeMacker(string nameSpace, string usingNameSpace, string className, Action<CodeMacker> eventCallBack = null)
            : this(nameSpace, usingNameSpace, className, TypeAttributes.Public, eventCallBack)
        {

        }
        public CodeMacker(string nameSpace, string usingNameSpace, string className, TypeAttributes visitAttr, Action<CodeMacker> eventCallBack = null)
            : this(nameSpace, usingNameSpace, className, visitAttr, "C:\\", eventCallBack)
        {

        }
        public CodeMacker(string nameSpace, string usingNameSpace, string className, TypeAttributes visitAttr, string fileFullPath, Action<CodeMacker> eventCallBack = null)
        {
            #region Verify Area
            if (string.IsNullOrEmpty(nameSpace))
            {
                throw new ArgumentException("命名空间不能为空");
            }
            if (string.IsNullOrEmpty(className))
            {
                throw new ArgumentException("类名不能为空");
            }
            #endregion

            if (eventCallBack != null)
            {
                eventCallBack(this);
            }
            if (_onecEventNotRun)
            {
                if (DoOnceWorkBeforeConstructor != null)
                {
                    DoOnceWorkBeforeConstructor();
                    _onecEventNotRun = false;
                }
            }

            if (BeforeConstructor != null)
            {
                BeforeConstructor();
            }

            #region Main
            _targetUnit = new CodeCompileUnit();
            _samples = new CodeNamespace(nameSpace);
            _samples.Imports.Add(new CodeNamespaceImport(usingNameSpace));
            _targetClass = new CodeTypeDeclaration(className);
            _targetClass.IsClass = true;
            _targetClass.TypeAttributes = visitAttr;
            _samples.Types.Add(_targetClass);
            _targetUnit.Namespaces.Add(_samples);

            NameSpace = nameSpace;
            ClassName = className;
            FullNameSpaceWithClass = NameSpace + "." + ClassName;

            _outputFileName = fileFullPath;
            #endregion

            if (AfterConstructor != null)
            {
                AfterConstructor();
            }
        }

        #endregion

 其实写了半天主要就是最后一个,剩下的我都自动默认了。

 默认构造函数可空,那里留了个Action,那是用来做扩展的,咱们最后再说,不过如果你踏踏实实的看下来了,应该也猜个差不多了。

剩下的就是初始化一些内容,如果你不填你创建的这个对象类名,命名空间啥的,我就随便给你写一份。反正你也不关心

 你只需要记住,在你new的时候,我会先触发一次且仅一次的callback给你做扩展,至于扩展啥,我也不知道。

然后开始了构建构造函数和基本的对象实例等等啥的。

在这里有2个时间点可以扩展,分别是构造前和构造后,2个callback

 然后没啥好说的了

==========================================白活线====================================================

下面看怎么加命名空间

#region NameSpaceAdded Function Area

        /// <summary>
        /// 新增命名空间
        /// </summary>
        /// <param name="codeNamespaceImport">命名空间文本,不需要添加using</param>
        public CodeMacker AddNamespace(string codeNamespaceImport)
            => AddNamespaces(() => new List<CodeNamespaceImport> { new CodeNamespaceImport(codeNamespaceImport) });

        /// <summary>
        /// 新增多个命名空间
        /// </summary>
        /// <param name="codeNamespaceImport">命名空间文本,不需要添加using</param>
        public CodeMacker AddNamespaces(List<string> codeNamespaceImport)
        {
            List<CodeNamespaceImport> codeNamespace = new List<CodeNamespaceImport>();
            codeNamespaceImport.ForEach(c => codeNamespace.Add(new CodeNamespaceImport(c)));
            return AddNamespaces(() => codeNamespace);
        }

        /// <summary>
        /// 新增命名空间 自定义
        /// 
        ///     Demo
        ///     var codeNamespace = new CodeNamespaceImport>("namespace");
        /// </summary>
        /// <param name="codeNamespaceImport"></param>
        public CodeMacker AddNamespace(Func<CodeNamespaceImport> codeNamespaceImport)
            => AddNamespaces(() => new List<CodeNamespaceImport> { codeNamespaceImport() });

        /// <summary>
        /// 新增命名空间 自定义
        /// 
        ///     Demo
        ///     var codeNamespace = new List<CodeNamespaceImport>()
        ///     {
        ///         new CodeNamespaceImport("namespace")
        ///     };
        /// </summary>
        /// <param name="codeNamespaceImport"></param>
        public CodeMacker AddNamespaces(Func<List<CodeNamespaceImport>> codeNamespaceImport)
        {
            if (BeforeAddNamespace != null)
            {
                BeforeAddNamespace();
            }
            codeNamespaceImport().ForEach(c => _samples.Imports.Add(c));
            if (AfterAddNamespace != null)
            {
                AfterAddNamespace();
            }
            return this;
        }
        #endregion

 

 这里,就是你引用包的一些地方,比如你这个类要引用一些个命名空间,就这玩意儿,用的时候不用加using

 

 

 调用很简单,就是直接传字符串,多的话扔个List

怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback

写Fun<T>的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。

 ==========================================白活线====================================================

 然后是构造函数,这里的构造函数是指的构造你这个生成对象的构造函数,不是构造这个类的方法

#region Constructor Function Area

        /// <summary>
        /// 添加构造函数
        /// </summary>
        /// <param name="ctor">ctor</param>
        public CodeMacker AddConstructor(ConstructorEntity ctor)
         => AddConstructor(() =>
            {
                if (ctor is null)
                {
                    throw new ArgumentException("构造函数基本访问类型参数不能为空");
                }
                // Declare the constructor
                CodeConstructor constructor = new CodeConstructor();
                constructor.Attributes = ctor.Attr;
                if (ctor.Params != null)
                {
                    ctor.Params.ForEach(s =>
                    {
                        // Add parameters.
                        constructor.Parameters.Add(new CodeParameterDeclarationExpression(
                            s.ParamType, s.Name));

                        if (!string.IsNullOrEmpty(s.ReferenceName))
                        {
                            // Add field initialization logic
                            CodeFieldReferenceExpression reference =
                                new CodeFieldReferenceExpression(
                                new CodeThisReferenceExpression(), s.ReferenceName);

                            constructor.Statements.Add(new CodeAssignStatement(reference,
                                new CodeArgumentReferenceExpression(s.Name)));
                        }

                    });
                }
                return constructor;
            });

        /// <summary>
        /// 添加构造函数
        /// </summary>
        /// <param name="ctor">ctor</param>
        public CodeMacker AddConstructor(Func<CodeConstructor> ctor)
        {
            if (BeforeAddConstructor != null)
            {
                BeforeAddConstructor();
            }

            _targetClass.Members.Add(ctor());

            if (AfterAddConstructor != null)
            {
                AfterAddConstructor();
            }
            return this;
        }

        #endregion

 

 怎么传参,New就可以了。比如你的构造函数要public A(int a,intb){}

那就看上一篇里面那个Entity的定义就好,吧参数对应写进去,参数名称,参数类型,给哪个参数赋值。

如果你构造函数不用默认参数,那写这个干啥,默认就是隐藏无参构造函数的。

 

 怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback

写Fun<T>的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。

  ==========================================白活线====================================================

然后是字段了

 

#region Field Function Area

        /// <summary>
        /// 新增字段
        /// </summary>
        /// <param name="FieldEntity">字段Model</param>
        public CodeMacker AddField(FieldEntity fieldModel)
            => AddField(() =>
            {
                if (fieldModel is null)
                {
                    throw new ArgumentException("字段参数信息不能为null");
                }
                return GetFieldBy(fieldModel);
            });

        /// <summary>
        /// 新增多个字段
        /// </summary>
        /// <param name="FieldEntity">字段Model</param>
        public CodeMacker AddFields(List<FieldEntity> fields)
        {
            fields.ForEach(f => AddField(f));
            return this;
        }

        /// <summary>
        /// 新增字段
        /// </summary>
        /// <param name="attr">字段标签</param>
        /// <param name="fieldName">字段名称</param>
        /// <param name="fieldType">字段类型</param>
        /// <param name="comment">字段注释</param>
        public CodeMacker AddField(MemberAttributes attr, string fieldName, Type fieldType, object defaultValue = default, string comment = null)
            => AddField(
                new FieldEntity(fieldName, fieldType)
                {
                    Attr = attr,
                    Comment = comment,
                    DefaultValue = defaultValue,
                });

        /// <summary>
        /// 新增字段(自定义)
        /// 
        /// 示例:
        ///         CodeMemberField field = new CodeMemberField();
        ///         field.Attributes = attr;
        ///         field.Name = fieldName;
        ///         field.Type = new CodeTypeReference(fieldType);
        ///         if (!string.IsNullOrEmpty(comment))
        ///         {
        ///             field.Comments.Add(new CodeCommentStatement(comment));
        ///         }
        ///         return field;
        /// </summary>
        /// <param name="fieldMember">字段类型</param>
        public CodeMacker AddField(Func<CodeMemberField> fieldMember)
            => AddFields(() => new List<CodeMemberField> { fieldMember() });

        /// <summary>
        /// 新增多个字段(自定义)
        /// 
        /// 
        ///         Demo:
        ///         List<CodeMemberField> fields = new List<CodeMemberField>();
        ///         CodeMemberField field = new CodeMemberField();
        ///         field.Attributes = attr;
        ///         field.Name = fieldName;
        ///         field.Type = new CodeTypeReference(fieldType);
        ///         if (!string.IsNullOrEmpty(comment))
        ///         {
        ///             field.Comments.Add(new CodeCommentStatement(comment));
        ///         }
        ///         fields.Add(field);
        ///         return fields;
        ///         
        /// </summary>
        /// <param name="fieldMember"></param>
        public CodeMacker AddFields(Func<List<CodeMemberField>> fieldMember)
        {
            if (BeforeAddField != null)
            {
                BeforeAddField();
            }
            fieldMember().ForEach(f => _targetClass.Members.Add(f));
            if (AfterAddField != null)
            {
                AfterAddField();
            }
            return this;
        }

        private CodeMemberField GetFieldBy(FieldEntity fieldModel)
        {
            // Declare the Value field.
            CodeMemberField field = new CodeMemberField(new CodeTypeReference(fieldModel.Type), fieldModel.Name);
            field.Attributes = fieldModel.Attr;
            if (fieldModel.DefaultValue != null)
            {
                field.InitExpression = new CodePrimitiveExpression(fieldModel.DefaultValue);
            }
            if (!string.IsNullOrEmpty(fieldModel.Comment))
            {
                field.Comments.Add(new CodeCommentStatement(fieldModel.Comment));
            }
            return field;
        }
        #endregion

 

字段就是把对象New进去,或者直接写参数,有留出来的一个方法,其实底下我也是自己new了一个,没啥区别,看使用习惯。

new的时候强制你要写名称和类型,都定好了,不写不行你,这个也没啥好说的,比较简单

 

 怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback

写Fun<T>的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。

  ==========================================白活线====================================================

然后是属性了,属性稍微有点东西讲一点

#region Properties Function Area

        /// <summary>
        /// 新增属性
        /// </summary>
        /// <param name="pro">属性Model</param>
        public CodeMacker AddPropertie(PropertyEntity pro)
            => AddProperties(() =>
            {
                if (pro is null)
                {
                    throw new ArgumentException("属性参数信息不能为null");
                }


                // Declare the read-only Width property.
                string fieldName = string.Empty;
                if (pro.HasGet && pro.HasSet)
                {
                    fieldName = pro.Name + " { get; set; }//";
                }
                else if (pro.HasGet && !pro.HasSet)
                {
                    fieldName = pro.Name + " { get; }//";
                }
                else
                {
                    throw new ArgumentException("属性不能设置只写或当成字段来使用");
                }

                var propertity = GetFieldBy(new FieldEntity(fieldName, pro.Type)
                {
                    Attr = pro.Attr,
                    Comment = pro.Comment
                });
                return new List<CodeTypeMember> { propertity };
            });


        /// <summary>
        /// 增加属性
        /// </summary>
        /// <param name="attr">属性标签</param>
        /// <param name="propertieName">属性名称</param>
        /// <param name="propertieType">属性类型</param>
        /// <param name="comment">属性注释</param>
        public CodeMacker AddPropertie(MemberAttributes attr, string propertieName, Type propertieType, string comment = null)
            => AddPropertie(new PropertyEntity(propertieName, propertieType)
            {
                HasGet = true,
                HasSet = true,
                Comment = comment
            });

        /// <summary>
        /// 添加多个属性
        /// </summary>
        /// <param name="pros"></param>
        public CodeMacker AddProperties(List<PropertyEntity> pros)
        {
            pros.ForEach(s => AddPropertie(s));
            return this;
        }

        /// <summary>
        /// 新增1个属性(自定义)
        /// </summary>
        /// <param name="propertyMember">Func CodeTypeMember</param>
        public CodeMacker AddPropertie(Func<CodeTypeMember> propertyMember)
            => AddProperties(() => new List<CodeTypeMember>
                {
                    propertyMember()
                }
            );

        /// <summary>
        /// 新增多个属性(自定义)
        /// </summary>
        /// <param name="propertyMember">Func list CodeTypeMember</param>
        public CodeMacker AddProperties(Func<List<CodeTypeMember>> propertyMember)
        {
            if (BeforeAddPropertie != null)
            {
                BeforeAddPropertie();
            }

            propertyMember().ForEach(p => _targetClass.Members.Add(p));

            if (AfterAddPropertie != null)
            {
                AfterAddPropertie();
            }
            return this;
        }

        #endregion

 

 

如果你,如果哈,如果你认真的看了方法,你就会发现,我特|么的不是还是字段吗,没错。就是这样

官方给的默认方法是这样的,如果是生成的属性,没有自动属性,必须得在get和set里写逻辑,但是说白了大多时候我们不需要这么做(懒)

所以就写个自动属性,但是问题在于官方没有给自动属性的操作方式。

在第一章里我说过,CodeDom本身是生成个字符串,所以费那脑子干嘛,

字段加点料,不就行了?(我才不会说我也是查到的,啊哈哈哈哈)

其他没有区别了,加多个,单个都可以。如果你有写get,set逻辑的需求,那就去调用func自己写。

但是需要你自己去学习CodeDom那些弯弯道道了,我反正是懒得写了。

 

怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback

写Fun<T>的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。

  ==========================================白活线====================================================

这里该说方法了,方法,很重要的一环。但是,异常简单。甚至没什么好说的。

#region Method Area

        /// <summary>
        /// 添加方法
        /// </summary>
        /// <param name="methods">方法</param>
        /// <returns>this</returns>
        public CodeMacker AddMethod(string method, string comment = null)
            => AddMethod(new MethodEntity { Method = method, Comment = comment });

        /// <summary>
        /// 添加单个方法
        /// </summary>
        /// <param name="methods">方法</param>
        /// <returns>this</returns>
        public CodeMacker AddMethod(MethodEntity method)
            => AddMethods(new List<MethodEntity> { method });

        /// <summary>
        /// 添加多个方法
        /// </summary>
        /// <param name="methods">方法集合</param>
        /// <returns>this</returns>
        public CodeMacker AddMethods(List<MethodEntity> methods)
            => AddMethods(() =>
            {
                var methodsList = new List<CodeTypeMember>();
                methods.ForEach(m =>
                {
                    CodeSnippetTypeMember snippet = new CodeSnippetTypeMember
                    {
                        Text = m.Method
                    };
                    if (!string.IsNullOrEmpty(m.Comment))
                    {
                        snippet.Comments.Add(new CodeCommentStatement(m.Comment, false));
                    }
                    methodsList.Add(snippet);
                });
                return methodsList;
            });


        /// <summary>
        /// 添加方法(自定义)
        /// </summary>
        /// <param name="method">Func<CodeTypeMember></param>
        public CodeMacker AddMethod(Func<CodeTypeMember> method)
            => AddMethods(() => new List<CodeTypeMember> { method() });

        /// <summary>
        /// 添加多个方法(自定义)
        /// </summary>
        /// <param name="method">Func<List<CodeTypeMember>></param>
        public CodeMacker AddMethods(Func<List<CodeTypeMember>> method)
        {
            if (BeforeAddMethod != null)
            {
                BeforeAddMethod();
            }

            method().ForEach(m => _targetClass.Members.Add(m));

            if (AfterAddMethod != null)
            {
                AfterAddMethod();
            }
            return this;
        }

        #endregion

 

其实看了这么多,你会发现,我写的代码都差不多,圈套圈的。实现就那一个。

本来方法是很复杂的一个内容,里面可能要写for,if,while,event,action ,obj.....

官方给的逻辑非常之复杂

复杂到我不想学了,但是,但是,但是我找到了一个非常简单的方法,那就是,你给我把方法传个字符串进来,我给你生成。

没错,就是字面意思。传个字符串。具体怎么用,后面有示例。

如果你有自定义生成的需求,那就调用Fun<T>的方法吧,自定义就可以。但是很麻烦。

 

怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback

写Fun<T>的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。

  ==========================================白活线====================================================

ok。到此为止,基本上都有了,命名空间,类,字段,属性,方法都齐活儿了。

那就应该是输出了对吧,。

来,我们看输出。

#region OutPut
        /// <summary>
        /// 控制台输出
        /// </summary>
        /// <returns></returns>
        public CodeMacker Log()
        {
            CodeDomProvider prvd = CodeDomProvider.CreateProvider("cs");
            prvd.GenerateCodeFromCompileUnit(_targetUnit, Console.Out, null);
            return this;
        }

        /// <summary>
        /// 文本输出(string)
        /// </summary>
        /// <param name="fileFullPath">文件地址</param>
        public string GenerateCSharpString()
            => CodeDomOutString(() =>
            {
                CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
                CodeGeneratorOptions options = new CodeGeneratorOptions { BracingStyle = "C" };

                using (StringWriter sourceWriter = new StringWriter())
                {
                    provider.GenerateCodeFromCompileUnit(_targetUnit, sourceWriter, options);
                    return sourceWriter.ToString();
                }
            });

        /// <summary>
        /// 自定义CodeDom输出(string)
        /// </summary>
        /// <param name="fileFullPath">文件地址</param>
        public string CodeDomOutString(Func<string> codeDomContext)
            => codeDomContext();


        /// <summary>
        /// 文件输出(.cs)
        /// </summary>
        /// <param name="fileFullPath">文件地址</param>
        public CodeMacker GenerateCSharpFile(string fileFullPath)
        {
            if (string.IsNullOrEmpty(fileFullPath))
            {
                throw new ArgumentException("文件输出路径为空,请设置输出路径!");
            }
            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
            CodeGeneratorOptions options = new CodeGeneratorOptions();
            options.BracingStyle = "C";
            using (StreamWriter sourceWriter = new StreamWriter(fileFullPath))
            {
                provider.GenerateCodeFromCompileUnit(
                    _targetUnit, sourceWriter, options);
            }
            return this;
        }

        /// <summary>
        /// 文件输出(.cs)
        /// </summary>
        public CodeMacker CodeDomOutFile()
            => GenerateCSharpFile(_outputFileName);
        #endregion

 

第一个是控制台输出,调试的时候用这个,能直接看到生成的对象类。

第二个是文本输出,也就是我们的核心方法,生成对象全靠它

第三个是自定义输出,你自己爱怎么玩怎么玩。

第四个是文件输出,如果你碰到生成对象后怎么调用也无法成功的时候,记住,输出个文本,你会找到问题的。v1=🤞😁😁😁

最后一个略过

 

怎么用就不说了,这里没有时间节点扩展,别找了。

写Fun<T>的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。

  ==========================================白活线====================================================

重头戏来了,怎么生成对象呢,就在这里

看代码先

 

        #region CreateInstance Function Area

        /// <summary>
        /// 创建单例对象 按命名空间+类名区分
        /// </summary>
        /// <returns></returns>
        public object CreateInstanceOfSingleton()
            => CreateInstanceOfSingleton(this.GenerateCSharpString(), this.FullNameSpaceWithClass);

        /// <summary>
        /// 创建单例对象  按命名空间+类名区分
        /// </summary>
        /// <param name="context">创建对象文本</param>
        /// <param name="fullNamespaceClass">命名空间+类名称</param>
        /// <returns></returns>
        public object CreateInstanceOfSingleton(string context, string fullNamespaceClass)
        {
            if (HasSingletonInstance(fullNamespaceClass))
            {
                return GetSingletonInstanceBy(fullNamespaceClass);
            }
            var instance = CreateInstance(context, fullNamespaceClass);
            _singletonContainer.Add(fullNamespaceClass, instance);
            return instance;
        }

        /// <summary>
        /// 根据本类构建对象
        /// </summary>
        /// <returns>返回Object类,根据内容反射获取信息</returns>
        public object CreateInstance()
            => CreateInstance(this.GenerateCSharpString(), this.FullNameSpaceWithClass);

        /// <summary>
        /// 根据传入内容构建对象
        /// </summary>
        /// <returns>返回Object类,根据内容反射获取信息</returns>
        public object CreateInstance(string context, string fullNamespaceClass)
            => CreateInstance(() =>
            {
                #region Verify
                if (string.IsNullOrEmpty(context))
                {
                    throw new ArgumentException("生成的代码不能为空");
                }
                if (string.IsNullOrEmpty(fullNamespaceClass))
                {
                    throw new ArgumentException("命名空间和类名称不能为空");
                }
                #endregion

                #region 加载构建
                var refPaths = new[]
                {
                    typeof(System.Object).GetTypeInfo().Assembly.Location,
                    typeof(Console).GetTypeInfo().Assembly.Location,
                    Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll")
                };
                MetadataReference[] references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray();


                CSharpCompilation compilation = CSharpCompilation.Create(
                    Path.GetRandomFileName(),
                    syntaxTrees: new[] { CSharpSyntaxTree.ParseText(context) },
                    references: references,
                    options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
                #endregion

                #region 创建对象
                using (var ms = new MemoryStream())
                {
                    EmitResult result = compilation.Emit(ms);

                    if (result.Success)
                    {
                        ms.Seek(0, SeekOrigin.Begin);

                        Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
                        //var type = assembly.GetType("CodeDOM.CodeDOMCreatedClass");
                        return assembly.CreateInstance(fullNamespaceClass);
                    }
                    else
                    {
                        return result.Diagnostics.Where(diagnostic =>
                                                    diagnostic.IsWarningAsError ||
                                                    diagnostic.Severity == DiagnosticSeverity.Error);
                    }
                }
                #endregion
            });

        /// <summary>
        /// 构建自定义生成方式和对象
        /// </summary>
        /// <returns>返回Object类,根据内容反射获取信息</returns>
        public object CreateInstance(Func<object> createInfo)
        {
            if (BeforeCreateInstance != null)
            {
                BeforeCreateInstance();
            }

            var resultObj = createInfo();

            if (AfterCreateInstance != null)
            {
                AfterCreateInstance();
            }

            return resultObj;
        }

        #endregion

        #region Singleton Ioc Function Area

        /// <summary>
        /// 获取单例对象
        /// </summary>
        /// <param name="key">命名空间+类名称</param>
        /// <returns></returns>
        public static object GetSingletonInstanceBy(string key)
            => HasSingletonInstance(key) ? _singletonContainer[key] : null;

        /// <summary>
        /// 是否包含单例对象
        /// </summary>
        /// <param name="key">命名空间+类名称</param>
        /// <returns></returns>
        public static bool HasSingletonInstance(string key)
            => _singletonContainer.ContainsKey(key);

        #endregion

 

这里我做了两套,一套是单例,一套是瞬时(普通new)至于为什么没有Scope,因为我没有Scope的作用域呀,啊哈哈哈哈啊

单例的方法是在最上面,有一个字典

     /// <summary>
        /// 单例IOC容器
        /// </summary>
        private static Dictionary<string, object> _singletonContainer = new Dictionary<string, object>();

 

从这里存取。

重点说生成实例方法。

CodeDom在FrameWork的时代里面是支持直接生成对象的,但是如果在NetCore或者Net5当中是不支持直接生成,会报平台错误,具体怎么我就不演示了

没有意义,如果你是FrameWork使用的话,可以找一找代码,那个很简单,几行。

我这里是用了Emit来进行操作,怎么个逻辑调用跑来跑去的就那一堆,我看了半天也懒得分析了,直接用吧,还挺好。性能,算了,这里我们不说性能,如果有好的意见也可以提出来,我看心情改,啊哈哈哈哈哈

这里就是把字符串传进去,然后生成对象,就这样。多余的内容我封装好了。

单例默认用命名空间+类来作为Key,你自定义也可以,传给我

 

怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback

写Fun<T>的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。

  ==========================================白活线====================================================

最后我们来看一下所有的时间节点。

     #region CodeMaker Filter 节点
        private static bool _onecEventNotRun = true;
        /// <summary>
        /// 整个项目运行中只调用一次的事件,事件发生点在尚未构造对象之前
        /// </summary>
        public event Action DoOnceWorkBeforeConstructor = null;

        /// <summary>
        /// 开始构造函数之前
        /// </summary>
        public event Action BeforeConstructor = null;
        /// <summary>
        /// 结束构造函数时
        /// </summary>
        public event Action AfterConstructor = null;

        /// <summary>
        /// 添加命名空间之前(生成代码 AddNamespace)
        /// </summary>
        public event Action BeforeAddNamespace = null;
        /// <summary>
        /// 添加命名空间之后(生成代码 AddNamespace)
        /// </summary>
        public event Action AfterAddNamespace = null;

        /// <summary>
        /// 添加构造函数之前(生成代码 AddConstructor)
        /// </summary>
        public event Action BeforeAddConstructor = null;
        /// <summary>
        /// 添加构造函数之后(生成代码 AddConstructor)
        /// </summary>
        public event Action AfterAddConstructor = null;

        /// <summary>
        /// 添加字段之前(生成代码 AddField)
        /// </summary>
        public event Action BeforeAddField = null;
        /// <summary>
        /// 添加字段之后(生成代码 AddField)
        /// </summary>
        public event Action AfterAddField = null;

        /// <summary>
        /// 添加属性之前(生成代码 AddPropertie)
        /// </summary>
        public event Action BeforeAddPropertie = null;
        /// <summary>
        /// 添加属性之后(生成代码 AddPropertie)
        /// </summary>
        public event Action AfterAddPropertie = null;

        /// <summary>
        /// 添加方法之前(生成代码 AddMethod)
        /// </summary>
        public event Action BeforeAddMethod = null;
        /// <summary>
        /// 添加方法之后(生成代码 AddMethod)
        /// </summary>
        public event Action AfterAddMethod = null;

        /// <summary>
        /// 创建对象之前(生成实例 CreateInstance)
        /// </summary>
        public event Action BeforeCreateInstance = null;
        /// <summary>
        /// 创建对象之后(生成实例 CreateInstance)
        /// </summary>
        public event Action AfterCreateInstance = null;

        #endregion

 

嗯,没什么好说的,在构造函数里初始化赋值就可以了。

 

 

好了,你们期待的Demo示例这里我不打算写了,因为我写累了。下一章里写,具体名字叫啥呢,就是CodeDom的完结吧,啊哈哈哈哈哈(恶习多多)

 

posted @ 2021-11-17 17:32  王月半子  阅读(387)  评论(2编辑  收藏  举报