嗯,这里就是最后一章了,至于为什么是红字,就是为了和前面假装同意一点,啊哈哈哈
先上源码,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 }
咱们开发,碰到不知道的类一般怎么办,那肯定是先 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的完结吧,啊哈哈哈哈哈(恶习多多)