动态创建类文件

动态创建类文件后,就可以使用上一篇文章[小技巧]C# .net 动态编程 (1)中的动态编译生成动态的对象了。这样就方便多了。

知识点

CodeDOM

效果

通过类动态生成cs类
就是写文件操作,为什么这样做呢,这让我联想到了WCF引用自动生成代码的东西。
以下是自动生成的类

  1. //------------------------------------------------------------------------------
  2. // <auto-generated>
  3. // 此代码由工具生成。
  4. // 运行时版本:4.0.30319.42000
  5. //
  6. // 对此文件的更改可能会导致不正确的行为,并且如果
  7. // 重新生成代码,这些更改将会丢失。
  8. // </auto-generated>
  9. //------------------------------------------------------------------------------
  10. namespace Test
  11. {
  12. using System;
  13. using System.Collections.Generic;
  14. public partial class Test
  15. {
  16. /// <summary>
  17. /// A
  18. /// </summary>
  19. private int A;
  20. /// <summary>
  21. /// b
  22. /// </summary>
  23. private string b;
  24. /// <summary>
  25. /// bList
  26. /// </summary>
  27. private System.Collections.Generic.List<string> bList;
  28. /// <summary>
  29. /// B
  30. /// </summary>
  31. public virtual string B
  32. {
  33. get
  34. {
  35. return this.b;
  36. }
  37. set
  38. {
  39. this.b = value;
  40. }
  41. }
  42. /// <summary>
  43. /// BList
  44. /// </summary>
  45. public virtual System.Collections.Generic.List<string> BList
  46. {
  47. get
  48. {
  49. return this.bList;
  50. }
  51. set
  52. {
  53. this.bList = value;
  54. }
  55. }
  56. }
  57. }

调用方式

  1. ClassCreator creator = new ClassCreator();
  2. creator.AddFields("A", typeof(int));
  3. creator.AddFields("A", typeof(string));
  4. creator.AddProperties("B", typeof(string));
  5. creator.AddProperties("BList", typeof(List<string>));
  6. if (creator.GenerateCode("Test", "Test"))
  7. Console.WriteLine("Success");
  8. else
  9. Console.WriteLine("Failed");

创建类的源代码

  1. using System;
  2. using System.CodeDom;
  3. using System.CodeDom.Compiler;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Text;
  9. namespace 动态编程
  10. {
  11. public class ClassCreator
  12. {
  13. /// <summary>
  14. /// Define the compile unit to use for code generation.
  15. /// </summary>
  16. private CodeCompileUnit targetUnit;
  17. /// <summary>
  18. /// The only class in the compile unit. This class contains 2 fields,
  19. /// 3 properties, a constructor, an entry point, and 1 simple method.
  20. /// </summary>
  21. private CodeTypeDeclaration targetClass;
  22. private List<string> namespaceNames;
  23. /// <summary>
  24. /// 字段
  25. /// </summary>
  26. private List<CodeMemberField> codeMemberFields;
  27. /// <summary>
  28. /// 属性
  29. /// </summary>
  30. private List<CodeMemberProperty> codeMemberPropertys;
  31. /// <summary>
  32. /// Define the class.
  33. /// </summary>
  34. public ClassCreator()
  35. {
  36. namespaceNames = new List<string>();
  37. codeMemberFields = new List<CodeMemberField>();
  38. codeMemberPropertys = new List<CodeMemberProperty>();
  39. }
  40. /// <summary>
  41. /// 添加字段
  42. /// </summary>
  43. /// <param name="fileName">字段名称</param>
  44. /// <param name="type">字段类型</param>
  45. /// <param name="visitLevel">访问级别 默认是private</param>
  46. /// <param name="comments">字段描述信息</param>
  47. public void AddFields(string fileName, Type type, MemberAttributes visitLevel = MemberAttributes.Private, string comments = null)
  48. {
  49. if (codeMemberFields.Exists(t => t.Name == fileName)) return;
  50. CodeMemberField field = new CodeMemberField();
  51. field.Attributes = visitLevel;
  52. field.Name = fileName;
  53. field.Type = new CodeTypeReference(type);
  54. field.Comments.Add(new CodeCommentStatement(
  55. " <summary>", true));
  56. field.Comments.Add(new CodeCommentStatement(
  57. comments ?? fileName, true));
  58. field.Comments.Add(new CodeCommentStatement(
  59. " </summary>", true));
  60. codeMemberFields.Add(field);
  61. AddNamespance(type);
  62. }
  63. /// <summary>
  64. /// 添加属性
  65. /// </summary>
  66. /// <param name="propertyName">属性名称</param>
  67. /// <param name="type">属性类型</param>
  68. /// <param name="comments">属性描述信息</param>
  69. public void AddProperties(string propertyName, Type type, bool hasGet = true, bool hasSet = true, string comments = null)
  70. {
  71. if (codeMemberPropertys.Exists(t => t.Name == propertyName)) return;
  72. CodeMemberProperty property = new CodeMemberProperty();
  73. property.Attributes = MemberAttributes.Public;
  74. property.Name = propertyName;
  75. property.HasGet = hasGet;
  76. property.HasSet = hasSet;
  77. property.Type = new CodeTypeReference(type);
  78. property.Comments.Add(new CodeCommentStatement(
  79. " <summary>", true));
  80. property.Comments.Add(new CodeCommentStatement(
  81. comments ?? propertyName, true));
  82. property.Comments.Add(new CodeCommentStatement(
  83. " </summary>", true));
  84. var fileName = (propertyName[0]).ToString().ToLower() + propertyName.Substring(1);
  85. if (!codeMemberFields.Exists(t => t.Name == fileName))
  86. AddFields(fileName, type, MemberAttributes.Private, comments);
  87. property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fileName)));
  88. CodeFieldReferenceExpression reference = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fileName);
  89. property.SetStatements.Add(new CodeAssignStatement(reference, new CodeArgumentReferenceExpression("value")));
  90. codeMemberPropertys.Add(property);
  91. AddNamespance(type);
  92. }
  93. private void AddNamespance(Type type)
  94. {
  95. if (namespaceNames.IndexOf(type.Namespace) == -1)
  96. namespaceNames.Add(type.Namespace);
  97. }
  98. /// <summary>
  99. /// 生成代码
  100. /// </summary>
  101. /// <param name="namespaceName">命名空间</param>
  102. /// <param name="className">类型</param>
  103. /// <param name="visitLevel">访问级别,默认是Public</param>
  104. /// <param name="filePath">文件完整路径,默认是程序所在目录,和类名同名</param>
  105. /// <returns>true | false</returns>
  106. public bool GenerateCode(string namespaceName, string className, TypeAttributes visitLevel = TypeAttributes.Public, string filePath = null)
  107. {
  108. try
  109. {
  110. targetUnit = new CodeCompileUnit();
  111. CodeNamespace newClass = new CodeNamespace(namespaceName);
  112. targetClass = new CodeTypeDeclaration(className);
  113. targetClass.IsClass = true;
  114. targetClass.TypeAttributes = visitLevel;
  115. targetClass.IsPartial = true;
  116. newClass.Types.Add(targetClass);
  117. targetUnit.Namespaces.Add(newClass);
  118. namespaceNames.ForEach(item =>
  119. {
  120. newClass.Imports.Add(new CodeNamespaceImport(item));
  121. });
  122. codeMemberFields.ForEach(item =>
  123. {
  124. targetClass.Members.Add(item);
  125. });
  126. codeMemberPropertys.ForEach(item =>
  127. {
  128. targetClass.Members.Add(item);
  129. });
  130. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
  131. CodeGeneratorOptions options = new CodeGeneratorOptions();
  132. options.BracingStyle = "C";
  133. using (StreamWriter sourceWriter = new StreamWriter(filePath ?? $"{className}.cs"))
  134. {
  135. provider.GenerateCodeFromCompileUnit(
  136. targetUnit, sourceWriter, options);
  137. }
  138. return true;
  139. }
  140. catch (Exception)
  141. {
  142. return false;
  143. }
  144. }
  145. }
  146. }

测试代码

  1. Test.Test t = new Test.Test() { B="aaaa"};
  2. Console.WriteLine(t.B);

运行效果

c1ba98864b7944e2877442b8ced7cb8c.png

总结

可以生成代码了,再根据上一篇的内容动态编译,一定可以实现动态编程的。

注:下一篇试下以下结合使用
https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/how-to-create-a-class-using-codedom
————————————————
版权声明:本文为CSDN博主「iml6yu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/iml6yu/article/details/119858749