Net5和NetCore可用
嗯,这里就是最后一章了,至于为什么是红字,就是为了和前面假装同意一点,啊哈哈哈
先上源码,900多行,我折叠了,具体怎么用看后面讲解。
public class CodeMake{#region Field Areaprivate 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 Ctorstatic 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 Areaif (string.IsNullOrEmpty(nameSpace)){throw new ArgumentException("命名空间不能为空");}if (string.IsNullOrEmpty(className)){throw new ArgumentException("类名不能为空");}#endregionif (eventCallBack != null){eventCallBack(this);}if (_onecEventNotRun){if (DoOnceWorkBeforeConstructor != null){DoOnceWorkBeforeConstructor();_onecEventNotRun = false;}}if (BeforeConstructor != null){BeforeConstructor();}#region Mainif (_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;#endregionif (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 constructorCodeConstructor 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 logicCodeFieldReferenceExpression 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 Verifyif (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 Ctorpublic 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 Areaif (string.IsNullOrEmpty(nameSpace)){throw new ArgumentException("命名空间不能为空");}if (string.IsNullOrEmpty(className)){throw new ArgumentException("类名不能为空");}#endregionif (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;#endregionif (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
==========================================白活线====================================================
然后是构造函数,这里的构造函数是指的构造你这个生成对象的构造函数,不是构造这个类的方法
#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 constructorCodeConstructor 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 logicCodeFieldReferenceExpression 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
==========================================白活线====================================================
然后是字段了
#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
==========================================白活线====================================================
然后是属性了,属性稍微有点东西讲一点
#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
==========================================白活线====================================================
这里该说方法了,方法,很重要的一环。但是,异常简单。甚至没什么好说的。
#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
怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback
写Fun
==========================================白活线====================================================
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
==========================================白活线====================================================
重头戏来了,怎么生成对象呢,就在这里
看代码先
#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 Verifyif (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
==========================================白活线====================================================
最后我们来看一下所有的时间节点。
#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的完结吧,啊哈哈哈哈哈(恶习多多)
————————————————
原文链接:https://www.cnblogs.com/SevenWang/p/15568399.html
