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

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

    1. public class CodeMake
    2. {
    3. #region Field Area
    4. private CodeNamespace _samples;
    5. private CodeCompileUnit _targetUnit;
    6. private CodeTypeDeclaration _targetClass;
    7. private readonly string _outputFileName;
    8. private static IList<string> _assemblyUsingLocation = null;
    9. private event Action _assemblyLoad = null;
    10. /// <summary>
    11. /// 单例IOC容器
    12. /// </summary>
    13. private static Dictionary<string, object> _singletonContainer = null;
    14. private static readonly object _lock_obj = new object();
    15. /// <summary>
    16. /// 命名空间
    17. /// </summary>
    18. public string NameSpace { get; private set; }
    19. /// <summary>
    20. /// 类名称
    21. /// </summary>
    22. public string ClassName { get; private set; }
    23. /// <summary>
    24. /// 命名空间+类名称
    25. /// </summary>
    26. public string FullNameSpaceWithClass { get; private set; }
    27. #region CodeMaker Filter 节点
    28. private static bool _onecEventNotRun = true;
    29. /// <summary>
    30. /// 整个项目运行中只调用一次的事件,事件发生点在尚未构造对象之前
    31. /// </summary>
    32. public event Action DoOnceWorkBeforeConstructor = null;
    33. /// <summary>
    34. /// 开始构造函数之前
    35. /// </summary>
    36. public event Action BeforeConstructor = null;
    37. /// <summary>
    38. /// 结束构造函数时
    39. /// </summary>
    40. public event Action AfterConstructor = null;
    41. /// <summary>
    42. /// 添加命名空间之前(生成代码 AddNamespace)
    43. /// </summary>
    44. public event Action BeforeAddNamespace = null;
    45. /// <summary>
    46. /// 添加命名空间之后(生成代码 AddNamespace)
    47. /// </summary>
    48. public event Action AfterAddNamespace = null;
    49. /// <summary>
    50. /// 添加构造函数之前(生成代码 AddConstructor)
    51. /// </summary>
    52. public event Action BeforeAddConstructor = null;
    53. /// <summary>
    54. /// 添加构造函数之后(生成代码 AddConstructor)
    55. /// </summary>
    56. public event Action AfterAddConstructor = null;
    57. /// <summary>
    58. /// 添加字段之前(生成代码 AddField)
    59. /// </summary>
    60. public event Action BeforeAddField = null;
    61. /// <summary>
    62. /// 添加字段之后(生成代码 AddField)
    63. /// </summary>
    64. public event Action AfterAddField = null;
    65. /// <summary>
    66. /// 添加属性之前(生成代码 AddPropertie)
    67. /// </summary>
    68. public event Action BeforeAddPropertie = null;
    69. /// <summary>
    70. /// 添加属性之后(生成代码 AddPropertie)
    71. /// </summary>
    72. public event Action AfterAddPropertie = null;
    73. /// <summary>
    74. /// 添加方法之前(生成代码 AddMethod)
    75. /// </summary>
    76. public event Action BeforeAddMethod = null;
    77. /// <summary>
    78. /// 添加方法之后(生成代码 AddMethod)
    79. /// </summary>
    80. public event Action AfterAddMethod = null;
    81. /// <summary>
    82. /// 创建对象之前(生成实例 CreateInstance)
    83. /// </summary>
    84. public event Action BeforeCreateInstance = null;
    85. /// <summary>
    86. /// 创建对象之后(生成实例 CreateInstance)
    87. /// </summary>
    88. public event Action AfterCreateInstance = null;
    89. #endregion
    90. #endregion
    91. #region Ctor
    92. static CodeMake()
    93. {
    94. if (_singletonContainer is null)
    95. {
    96. lock (_lock_obj)
    97. {
    98. if (_singletonContainer is null)
    99. {
    100. _singletonContainer = new Dictionary<string, object>();
    101. }
    102. }
    103. }
    104. if (_assemblyUsingLocation is null)
    105. {
    106. lock (_lock_obj)
    107. {
    108. if (_assemblyUsingLocation is null)
    109. {
    110. _assemblyUsingLocation = new List<string>();
    111. }
    112. }
    113. }
    114. }
    115. public CodeMake(bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
    116. : this("CodeDOM", reLoadAssembly, eventCallBack)
    117. {
    118. }
    119. public CodeMake(string nameSpace, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
    120. : this(nameSpace, "System", reLoadAssembly, eventCallBack)
    121. {
    122. }
    123. public CodeMake(string nameSpace, string usingNameSpace, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
    124. : this(nameSpace, usingNameSpace, "CreatedClass", reLoadAssembly, eventCallBack)
    125. {
    126. }
    127. public CodeMake(string nameSpace, string usingNameSpace, string className, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
    128. : this(nameSpace, usingNameSpace, className, TypeAttributes.Public, reLoadAssembly, eventCallBack)
    129. {
    130. }
    131. public CodeMake(string nameSpace, string usingNameSpace, string className, TypeAttributes visitAttr, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
    132. : this(nameSpace, usingNameSpace, className, visitAttr, "C:\\", reLoadAssembly, eventCallBack)
    133. {
    134. }
    135. public CodeMake(string nameSpace, string usingNameSpace, string className, TypeAttributes visitAttr, string fileFullPath, bool reLoadAssembly = false, Action<CodeMake> eventCallBack = null)
    136. {
    137. #region Verify Area
    138. if (string.IsNullOrEmpty(nameSpace))
    139. {
    140. throw new ArgumentException("命名空间不能为空");
    141. }
    142. if (string.IsNullOrEmpty(className))
    143. {
    144. throw new ArgumentException("类名不能为空");
    145. }
    146. #endregion
    147. if (eventCallBack != null)
    148. {
    149. eventCallBack(this);
    150. }
    151. if (_onecEventNotRun)
    152. {
    153. if (DoOnceWorkBeforeConstructor != null)
    154. {
    155. DoOnceWorkBeforeConstructor();
    156. _onecEventNotRun = false;
    157. }
    158. }
    159. if (BeforeConstructor != null)
    160. {
    161. BeforeConstructor();
    162. }
    163. #region Main
    164. if (_assemblyUsingLocation.Count <= 0)
    165. {
    166. _assemblyLoad += () => LoadBasicAssembly();
    167. }
    168. if (reLoadAssembly)
    169. {
    170. _assemblyLoad += () => LoadBasicAssembly();
    171. }
    172. _targetUnit = new CodeCompileUnit();
    173. _samples = new CodeNamespace(nameSpace);
    174. _samples.Imports.Add(new CodeNamespaceImport(usingNameSpace));
    175. _targetClass = new CodeTypeDeclaration(className);
    176. _targetClass.IsClass = true;
    177. _targetClass.TypeAttributes = visitAttr;
    178. _samples.Types.Add(_targetClass);
    179. _targetUnit.Namespaces.Add(_samples);
    180. NameSpace = nameSpace;
    181. ClassName = className;
    182. FullNameSpaceWithClass = NameSpace + "." + ClassName;
    183. _outputFileName = fileFullPath;
    184. #endregion
    185. if (AfterConstructor != null)
    186. {
    187. AfterConstructor();
    188. }
    189. }
    190. #endregion
    191. #region AssemblyLoadLocation Function Area
    192. /// <summary>
    193. /// 基础程序集加载
    194. /// </summary>
    195. private void LoadBasicAssembly()
    196. {
    197. if (_assemblyUsingLocation.Count > 0)
    198. {
    199. _assemblyUsingLocation.Clear();
    200. }
    201. DirectoryInfo root1 = new DirectoryInfo(AppContext.BaseDirectory);
    202. foreach (FileInfo f in root1.GetFiles())
    203. {
    204. if (f.Name.Contains(".dll", StringComparison.OrdinalIgnoreCase))
    205. {
    206. AddedAssemblyBy(f.FullName);
    207. }
    208. }
    209. AddedAssemblyBy(typeof(System.Object).GetTypeInfo().Assembly.Location);
    210. AddedAssemblyBy(typeof(Console).GetTypeInfo().Assembly.Location);
    211. AddedAssemblyBy(Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll"));
    212. }
    213. /// <summary>
    214. /// 加载程序集
    215. /// </summary>
    216. /// <param name="location"></param>
    217. private void AddedAssemblyBy(string location)
    218. {
    219. if (!_assemblyUsingLocation.Any(s => s.Contains(location)))
    220. {
    221. _assemblyUsingLocation.Add(location);
    222. }
    223. }
    224. /// <summary>
    225. /// 自定义一个生成对象引用的程序集扩展
    226. /// </summary>
    227. /// <param name="assemblyLocations"></param>
    228. /// <returns></returns>
    229. public CodeMake AddAssembly(string assemblyLocation)
    230. => AddAssemblys(new List<string> { assemblyLocation });
    231. /// <summary>
    232. /// 自定义一组生成对象引用的程序集扩展
    233. /// </summary>
    234. /// <param name="assemblyLocations"></param>
    235. /// <returns></returns>
    236. public CodeMake AddAssemblys(List<string> assemblyLocations)
    237. {
    238. foreach (var location in assemblyLocations)
    239. {
    240. _assemblyLoad += () => AddedAssemblyBy(location);
    241. }
    242. return this;
    243. }
    244. #endregion
    245. #region NameSpaceAdded Function Area
    246. /// <summary>
    247. /// 新增命名空间
    248. /// </summary>
    249. /// <param name="codeNamespaceImport">命名空间文本,不需要添加using</param>
    250. public CodeMake AddNamespace(string codeNamespaceImport)
    251. => AddNamespaces(() => new List<CodeNamespaceImport> { new CodeNamespaceImport(codeNamespaceImport) });
    252. /// <summary>
    253. /// 新增多个命名空间
    254. /// </summary>
    255. /// <param name="codeNamespaceImport">命名空间文本,不需要添加using</param>
    256. public CodeMake AddNamespaces(List<string> codeNamespaceImport)
    257. {
    258. List<CodeNamespaceImport> codeNamespace = new List<CodeNamespaceImport>();
    259. codeNamespaceImport.ForEach(c => codeNamespace.Add(new CodeNamespaceImport(c)));
    260. return AddNamespaces(() => codeNamespace);
    261. }
    262. /// <summary>
    263. /// 新增命名空间 自定义
    264. ///
    265. /// Demo
    266. /// var codeNamespace = new CodeNamespaceImport>("namespace");
    267. /// </summary>
    268. /// <param name="codeNamespaceImport"></param>
    269. public CodeMake AddNamespace(Func<CodeNamespaceImport> codeNamespaceImport)
    270. => AddNamespaces(() => new List<CodeNamespaceImport> { codeNamespaceImport() });
    271. /// <summary>
    272. /// 新增命名空间 自定义
    273. ///
    274. /// Demo
    275. /// var codeNamespace = new List<CodeNamespaceImport>()
    276. /// {
    277. /// new CodeNamespaceImport("namespace")
    278. /// };
    279. /// </summary>
    280. /// <param name="codeNamespaceImport"></param>
    281. public CodeMake AddNamespaces(Func<List<CodeNamespaceImport>> codeNamespaceImport)
    282. {
    283. if (BeforeAddNamespace != null)
    284. {
    285. BeforeAddNamespace();
    286. }
    287. codeNamespaceImport().ForEach(c => _samples.Imports.Add(c));
    288. if (AfterAddNamespace != null)
    289. {
    290. AfterAddNamespace();
    291. }
    292. return this;
    293. }
    294. #endregion
    295. #region Inherit Function Area
    296. /// <summary>
    297. /// 继承接口名称
    298. /// </summary>
    299. /// <param name="name"></param>
    300. /// <returns></returns>
    301. public CodeMake AddInherit(string name)
    302. {
    303. _targetClass.BaseTypes.Add(name);
    304. return this;
    305. }
    306. /// <summary>
    307. /// 继承接口类型
    308. /// </summary>
    309. /// <param name="name"></param>
    310. /// <returns></returns>
    311. public CodeMake AddInherit(Type name)
    312. {
    313. _targetClass.BaseTypes.Add(name);
    314. return this;
    315. }
    316. #endregion
    317. #region Constructor Function Area
    318. /// <summary>
    319. /// 添加构造函数
    320. /// </summary>
    321. /// <param name="ctor">ctor</param>
    322. public CodeMake AddConstructor(ConstructorEntity ctor)
    323. => AddConstructor(() =>
    324. {
    325. if (ctor is null)
    326. {
    327. throw new ArgumentException("构造函数基本访问类型参数不能为空");
    328. }
    329. // Declare the constructor
    330. CodeConstructor constructor = new CodeConstructor();
    331. constructor.Attributes = ctor.Attr;
    332. if (ctor.Params != null)
    333. {
    334. ctor.Params.ForEach(s =>
    335. {
    336. // Add parameters.
    337. constructor.Parameters.Add(new CodeParameterDeclarationExpression(
    338. s.ParamType, s.Name));
    339. if (!string.IsNullOrEmpty(s.ReferenceName))
    340. {
    341. // Add field initialization logic
    342. CodeFieldReferenceExpression reference =
    343. new CodeFieldReferenceExpression(
    344. new CodeThisReferenceExpression(), s.ReferenceName);
    345. constructor.Statements.Add(new CodeAssignStatement(reference,
    346. new CodeArgumentReferenceExpression(s.Name)));
    347. }
    348. });
    349. }
    350. return constructor;
    351. });
    352. /// <summary>
    353. /// 添加构造函数
    354. /// </summary>
    355. /// <param name="ctor">ctor</param>
    356. public CodeMake AddConstructor(Func<CodeConstructor> ctor)
    357. {
    358. if (BeforeAddConstructor != null)
    359. {
    360. BeforeAddConstructor();
    361. }
    362. _targetClass.Members.Add(ctor());
    363. if (AfterAddConstructor != null)
    364. {
    365. AfterAddConstructor();
    366. }
    367. return this;
    368. }
    369. #endregion
    370. #region Field Function Area
    371. /// <summary>
    372. /// 新增字段
    373. /// </summary>
    374. /// <param name="FieldEntity">字段Model</param>
    375. public CodeMake AddField(FieldEntity fieldModel)
    376. => AddField(() =>
    377. {
    378. if (fieldModel is null)
    379. {
    380. throw new ArgumentException("字段参数信息不能为null");
    381. }
    382. return GetFieldBy(fieldModel);
    383. });
    384. /// <summary>
    385. /// 新增多个字段
    386. /// </summary>
    387. /// <param name="FieldEntity">字段Model</param>
    388. public CodeMake AddFields(List<FieldEntity> fields)
    389. {
    390. fields.ForEach(f => AddField(f));
    391. return this;
    392. }
    393. /// <summary>
    394. /// 新增字段
    395. /// </summary>
    396. /// <param name="attr">字段标签</param>
    397. /// <param name="fieldName">字段名称</param>
    398. /// <param name="fieldType">字段类型</param>
    399. /// <param name="comment">字段注释</param>
    400. public CodeMake AddField(string fieldName, Type fieldType, MemberAttributes attr = MemberAttributes.Public , object defaultValue = default, string comment = null)
    401. => AddField(
    402. new FieldEntity(fieldName, fieldType)
    403. {
    404. Attr = attr,
    405. Comment = comment,
    406. DefaultValue = defaultValue,
    407. });
    408. /// <summary>
    409. /// 新增字段(自定义)
    410. ///
    411. /// 示例:
    412. /// CodeMemberField field = new CodeMemberField();
    413. /// field.Attributes = attr;
    414. /// field.Name = fieldName;
    415. /// field.Type = new CodeTypeReference(fieldType);
    416. /// if (!string.IsNullOrEmpty(comment))
    417. /// {
    418. /// field.Comments.Add(new CodeCommentStatement(comment));
    419. /// }
    420. /// return field;
    421. /// </summary>
    422. /// <param name="fieldMember">字段类型</param>
    423. public CodeMake AddField(Func<CodeMemberField> fieldMember)
    424. => AddFields(() => new List<CodeMemberField> { fieldMember() });
    425. /// <summary>
    426. /// 新增多个字段(自定义)
    427. ///
    428. ///
    429. /// Demo:
    430. /// List<CodeMemberField> fields = new List<CodeMemberField>();
    431. /// CodeMemberField field = new CodeMemberField();
    432. /// field.Attributes = attr;
    433. /// field.Name = fieldName;
    434. /// field.Type = new CodeTypeReference(fieldType);
    435. /// if (!string.IsNullOrEmpty(comment))
    436. /// {
    437. /// field.Comments.Add(new CodeCommentStatement(comment));
    438. /// }
    439. /// fields.Add(field);
    440. /// return fields;
    441. ///
    442. /// </summary>
    443. /// <param name="fieldMember"></param>
    444. public CodeMake AddFields(Func<List<CodeMemberField>> fieldMember)
    445. {
    446. if (BeforeAddField != null)
    447. {
    448. BeforeAddField();
    449. }
    450. fieldMember().ForEach(f => _targetClass.Members.Add(f));
    451. if (AfterAddField != null)
    452. {
    453. AfterAddField();
    454. }
    455. return this;
    456. }
    457. private CodeMemberField GetFieldBy(FieldEntity fieldModel)
    458. {
    459. // Declare the Value field.
    460. CodeMemberField field = new CodeMemberField(new CodeTypeReference(fieldModel.Type), fieldModel.Name);
    461. field.Attributes = fieldModel.Attr;
    462. if (fieldModel.DefaultValue != null)
    463. {
    464. field.InitExpression = new CodePrimitiveExpression(fieldModel.DefaultValue);
    465. }
    466. if (!string.IsNullOrEmpty(fieldModel.Comment))
    467. {
    468. field.Comments.Add(new CodeCommentStatement(fieldModel.Comment));
    469. }
    470. return field;
    471. }
    472. #endregion
    473. #region Properties Function Area
    474. /// <summary>
    475. /// 新增属性
    476. /// </summary>
    477. /// <param name="pro">属性Model</param>
    478. public CodeMake AddPropertie(PropertyEntity pro)
    479. => AddProperties(() =>
    480. {
    481. if (pro is null)
    482. {
    483. throw new ArgumentException("属性参数信息不能为null");
    484. }
    485. // Declare the read-only Width property.
    486. string fieldName = string.Empty;
    487. if (pro.HasGet && pro.HasSet)
    488. {
    489. fieldName = pro.Name + " { get; set; }//";
    490. }
    491. else if (pro.HasGet && !pro.HasSet)
    492. {
    493. fieldName = pro.Name + " { get; }//";
    494. }
    495. else
    496. {
    497. throw new ArgumentException("属性不能设置只写或当成字段来使用");
    498. }
    499. var propertity = GetFieldBy(new FieldEntity(fieldName, pro.Type)
    500. {
    501. Attr = pro.Attr,
    502. Comment = pro.Comment
    503. });
    504. return new List<CodeTypeMember> { propertity };
    505. });
    506. /// <summary>
    507. /// 增加属性
    508. /// </summary>
    509. /// <param name="attr">属性标签</param>
    510. /// <param name="propertieName">属性名称</param>
    511. /// <param name="propertieType">属性类型</param>
    512. /// <param name="comment">属性注释</param>
    513. public CodeMake AddPropertie(MemberAttributes attr, string propertieName, Type propertieType, string comment = null)
    514. => AddPropertie(new PropertyEntity(propertieName, propertieType)
    515. {
    516. HasGet = true,
    517. HasSet = true,
    518. Comment = comment
    519. });
    520. /// <summary>
    521. /// 添加多个属性
    522. /// </summary>
    523. /// <param name="pros"></param>
    524. public CodeMake AddProperties(List<PropertyEntity> pros)
    525. {
    526. pros.ForEach(s => AddPropertie(s));
    527. return this;
    528. }
    529. /// <summary>
    530. /// 新增1个属性(自定义)
    531. /// </summary>
    532. /// <param name="propertyMember">Func CodeTypeMember</param>
    533. public CodeMake AddPropertie(Func<CodeTypeMember> propertyMember)
    534. => AddProperties(() => new List<CodeTypeMember>
    535. {
    536. propertyMember()
    537. }
    538. );
    539. /// <summary>
    540. /// 新增多个属性(自定义)
    541. /// </summary>
    542. /// <param name="propertyMember">Func list CodeTypeMember</param>
    543. public CodeMake AddProperties(Func<List<CodeTypeMember>> propertyMember)
    544. {
    545. if (BeforeAddPropertie != null)
    546. {
    547. BeforeAddPropertie();
    548. }
    549. propertyMember().ForEach(p => _targetClass.Members.Add(p));
    550. if (AfterAddPropertie != null)
    551. {
    552. AfterAddPropertie();
    553. }
    554. return this;
    555. }
    556. #endregion
    557. #region Method Area
    558. /// <summary>
    559. /// 添加方法
    560. /// </summary>
    561. /// <param name="methods">方法</param>
    562. /// <returns>this</returns>
    563. public CodeMake AddMethod(string method, string comment = null)
    564. => AddMethod(new MethodEntity { Method = method, Comment = comment });
    565. /// <summary>
    566. /// 添加单个方法
    567. /// </summary>
    568. /// <param name="methods">方法</param>
    569. /// <returns>this</returns>
    570. public CodeMake AddMethod(MethodEntity method)
    571. => AddMethods(new List<MethodEntity> { method });
    572. /// <summary>
    573. /// 添加多个方法
    574. /// </summary>
    575. /// <param name="methods">方法集合</param>
    576. /// <returns>this</returns>
    577. public CodeMake AddMethods(List<MethodEntity> methods)
    578. => AddMethods(() =>
    579. {
    580. var methodsList = new List<CodeTypeMember>();
    581. methods.ForEach(m =>
    582. {
    583. CodeSnippetTypeMember snippet = new CodeSnippetTypeMember
    584. {
    585. Text = m.Method
    586. };
    587. if (!string.IsNullOrEmpty(m.Comment))
    588. {
    589. snippet.Comments.Add(new CodeCommentStatement(m.Comment, false));
    590. }
    591. methodsList.Add(snippet);
    592. });
    593. return methodsList;
    594. });
    595. /// <summary>
    596. /// 添加方法(自定义)
    597. /// </summary>
    598. /// <param name="method">Func<CodeTypeMember></param>
    599. public CodeMake AddMethod(Func<CodeTypeMember> method)
    600. => AddMethods(() => new List<CodeTypeMember> { method() });
    601. /// <summary>
    602. /// 添加多个方法(自定义)
    603. /// </summary>
    604. /// <param name="method">Func<List<CodeTypeMember>></param>
    605. public CodeMake AddMethods(Func<List<CodeTypeMember>> method)
    606. {
    607. if (BeforeAddMethod != null)
    608. {
    609. BeforeAddMethod();
    610. }
    611. method().ForEach(m => _targetClass.Members.Add(m));
    612. if (AfterAddMethod != null)
    613. {
    614. AfterAddMethod();
    615. }
    616. return this;
    617. }
    618. #endregion
    619. #region OutPut
    620. /// <summary>
    621. /// 控制台输出
    622. /// </summary>
    623. /// <returns></returns>
    624. public CodeMake Log()
    625. {
    626. Console.WriteLine(GenerateCSharpString());
    627. return this;
    628. }
    629. /// <summary>
    630. /// 元数据引用控制台输出
    631. /// </summary>
    632. /// <returns></returns>
    633. public CodeMake MetadataLog()
    634. {
    635. foreach (var item in _assemblyUsingLocation)
    636. {
    637. Console.WriteLine(item);
    638. }
    639. return this;
    640. }
    641. /// <summary>
    642. /// 文本输出(string)
    643. /// </summary>
    644. /// <param name="fileFullPath">文件地址</param>
    645. public string GenerateCSharpString()
    646. => CodeDomOutString(() =>
    647. {
    648. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
    649. CodeGeneratorOptions options = new CodeGeneratorOptions { BracingStyle = "C" };
    650. using (StringWriter sourceWriter = new StringWriter())
    651. {
    652. provider.GenerateCodeFromCompileUnit(_targetUnit, sourceWriter, options);
    653. return sourceWriter.ToString();
    654. }
    655. });
    656. /// <summary>
    657. /// 自定义CodeDom输出(string)
    658. /// </summary>
    659. /// <param name="fileFullPath">文件地址</param>
    660. public string CodeDomOutString(Func<string> codeDomContext)
    661. => codeDomContext();
    662. /// <summary>
    663. /// 文件输出(.cs)
    664. /// </summary>
    665. /// <param name="fileFullPath">文件地址</param>
    666. public CodeMake GenerateCSharpFile(string fileFullPath)
    667. {
    668. if (string.IsNullOrEmpty(fileFullPath))
    669. {
    670. throw new ArgumentException("文件输出路径为空,请设置输出路径!");
    671. }
    672. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
    673. CodeGeneratorOptions options = new CodeGeneratorOptions();
    674. options.BracingStyle = "C";
    675. using (StreamWriter sourceWriter = new StreamWriter(fileFullPath))
    676. {
    677. provider.GenerateCodeFromCompileUnit(
    678. _targetUnit, sourceWriter, options);
    679. }
    680. return this;
    681. }
    682. /// <summary>
    683. /// 文件输出(.cs)
    684. /// </summary>
    685. public CodeMake CodeDomOutFile()
    686. => GenerateCSharpFile(_outputFileName);
    687. #endregion
    688. #region CreateInstance Function Area
    689. /// <summary>
    690. /// 创建单例对象 默认获取方式为命名空间+类名
    691. /// </summary>
    692. /// <returns></returns>
    693. public object CreateInstanceOfSingleton()
    694. => CreateInstanceOfSingleton(this.GenerateCSharpString(), this.FullNameSpaceWithClass);
    695. /// <summary>
    696. /// 创建单例对象 存取Key自定义
    697. /// </summary>
    698. /// <param name="singletonKey"></param>
    699. /// <returns></returns>
    700. public object CreateInstanceOfSingleton(string singletonKey)
    701. => CreateInstanceOfSingleton(this.GenerateCSharpString(), singletonKey);
    702. /// <summary>
    703. /// 创建单例对象 按命名空间+类名区分
    704. /// </summary>
    705. /// <param name="context">创建对象文本</param>
    706. /// <param name="singletonKey">命名空间+类名称</param>
    707. /// <returns></returns>
    708. public object CreateInstanceOfSingleton(string context, string singletonKey)
    709. {
    710. if (HasSingletonInstance(singletonKey))
    711. {
    712. return GetSingletonInstanceBy(singletonKey);
    713. }
    714. var instance = CreateInstance(context, this.FullNameSpaceWithClass);
    715. _singletonContainer.Add(singletonKey, instance);
    716. return instance;
    717. }
    718. /// <summary>
    719. /// 根据本类构建对象
    720. /// </summary>
    721. /// <returns>返回Object类,根据内容反射获取信息</returns>
    722. public object CreateInstance()
    723. => CreateInstance(this.GenerateCSharpString(), this.FullNameSpaceWithClass);
    724. /// <summary>
    725. /// 根据传入内容构建对象
    726. /// </summary>
    727. /// <returns>返回Object类,根据内容反射获取信息</returns>
    728. public object CreateInstance(string context, string fullNamespaceClass)
    729. => CreateInstance(() =>
    730. {
    731. #region Verify
    732. if (string.IsNullOrEmpty(context))
    733. {
    734. throw new ArgumentException("生成的代码不能为空");
    735. }
    736. if (string.IsNullOrEmpty(fullNamespaceClass))
    737. {
    738. throw new ArgumentException("命名空间和类名称不能为空");
    739. }
    740. #endregion
    741. #region 加载构建
    742. //元数据加载
    743. if (_assemblyLoad != null)
    744. {
    745. _assemblyLoad();
    746. }
    747. MetadataReference[] references = _assemblyUsingLocation.ToArray().Select(r => MetadataReference.CreateFromFile(r)).ToArray();
    748. CSharpCompilation compilation = CSharpCompilation.Create(
    749. Path.GetRandomFileName(),
    750. syntaxTrees: new[] { CSharpSyntaxTree.ParseText(context) },
    751. references: references,
    752. options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
    753. #endregion
    754. #region 创建对象
    755. using (var ms = new MemoryStream())
    756. {
    757. EmitResult result = compilation.Emit(ms);
    758. if (result.Success)
    759. {
    760. ms.Seek(0, SeekOrigin.Begin);
    761. Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
    762. //var type = assembly.GetType("CodeDOM.CodeDOMCreatedClass");
    763. return assembly.CreateInstance(fullNamespaceClass);
    764. }
    765. else
    766. {
    767. return result.Diagnostics.Where(diagnostic =>
    768. diagnostic.IsWarningAsError ||
    769. diagnostic.Severity == DiagnosticSeverity.Error);
    770. }
    771. }
    772. #endregion
    773. });
    774. /// <summary>
    775. /// 构建自定义生成方式和对象
    776. /// </summary>
    777. /// <returns>返回Object类,根据内容反射获取信息</returns>
    778. public object CreateInstance(Func<object> createInfo)
    779. {
    780. if (BeforeCreateInstance != null)
    781. {
    782. BeforeCreateInstance();
    783. }
    784. var resultObj = createInfo();
    785. if (AfterCreateInstance != null)
    786. {
    787. AfterCreateInstance();
    788. }
    789. return resultObj;
    790. }
    791. #endregion
    792. #region Singleton Ioc Function Area
    793. /// <summary>
    794. /// 获取单例对象
    795. /// </summary>
    796. /// <param name="key">命名空间+类名称</param>
    797. /// <returns></returns>
    798. public static object GetSingletonInstanceBy(string key)
    799. => HasSingletonInstance(key) ? _singletonContainer[key] : null;
    800. /// <summary>
    801. /// 是否包含单例对象
    802. /// </summary>
    803. /// <param name="key">命名空间+类名称</param>
    804. /// <returns></returns>
    805. public static bool HasSingletonInstance(string key)
    806. => _singletonContainer.ContainsKey(key);
    807. #endregion
    808. }
    809. CodeMaker

    咱们开发,碰到不知道的类一般怎么办,那肯定是先 new一个,再看看参数再说,然后连蒙带猜的写。
    所以,我们说一些私有字段 然后讲构造函数。
    使用起来大多数人都是

    1. CodeMacker code = new CodeMacker();

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

    1. private CodeNamespace _samples;
    2. private CodeCompileUnit _targetUnit;
    3. private CodeTypeDeclaration _targetClass;
    4. private readonly string _outputFileName;
    5. /// <summary>
    6. /// 命名空间
    7. /// </summary>
    8. public string NameSpace { get; private set; }
    9. /// <summary>
    10. /// 类名称
    11. /// </summary>
    12. public string ClassName { get; private set; }
    13. /// <summary>
    14. /// 命名空间+类名称
    15. /// </summary>
    16. public string FullNameSpaceWithClass { get; private set; }

    这几个是基本需要的参数,干嘛的就看名称猜吧,具体实现讲起来太累,看官网文档好点。
    如果看了上面源码的就会发现少了点东西,没有了 一个字典和一堆Event,那个等会再说。

    然后我们看构造函数

    1. #region Ctor
    2. public CodeMacker(Action<CodeMacker> eventCallBack = null)
    3. : this("CodeDOM", eventCallBack)
    4. {
    5. }
    6. public CodeMacker(string nameSpace,Action<CodeMacker> eventCallBack = null)
    7. : this(nameSpace, "System", eventCallBack)
    8. {
    9. }
    10. public CodeMacker(string nameSpace, string usingNameSpace, Action<CodeMacker> eventCallBack = null)
    11. : this(nameSpace, usingNameSpace, "CreatedClass", eventCallBack)
    12. {
    13. }
    14. public CodeMacker(string nameSpace, string usingNameSpace, string className, Action<CodeMacker> eventCallBack = null)
    15. : this(nameSpace, usingNameSpace, className, TypeAttributes.Public, eventCallBack)
    16. {
    17. }
    18. public CodeMacker(string nameSpace, string usingNameSpace, string className, TypeAttributes visitAttr, Action<CodeMacker> eventCallBack = null)
    19. : this(nameSpace, usingNameSpace, className, visitAttr, "C:\\", eventCallBack)
    20. {
    21. }
    22. public CodeMacker(string nameSpace, string usingNameSpace, string className, TypeAttributes visitAttr, string fileFullPath, Action<CodeMacker> eventCallBack = null)
    23. {
    24. #region Verify Area
    25. if (string.IsNullOrEmpty(nameSpace))
    26. {
    27. throw new ArgumentException("命名空间不能为空");
    28. }
    29. if (string.IsNullOrEmpty(className))
    30. {
    31. throw new ArgumentException("类名不能为空");
    32. }
    33. #endregion
    34. if (eventCallBack != null)
    35. {
    36. eventCallBack(this);
    37. }
    38. if (_onecEventNotRun)
    39. {
    40. if (DoOnceWorkBeforeConstructor != null)
    41. {
    42. DoOnceWorkBeforeConstructor();
    43. _onecEventNotRun = false;
    44. }
    45. }
    46. if (BeforeConstructor != null)
    47. {
    48. BeforeConstructor();
    49. }
    50. #region Main
    51. _targetUnit = new CodeCompileUnit();
    52. _samples = new CodeNamespace(nameSpace);
    53. _samples.Imports.Add(new CodeNamespaceImport(usingNameSpace));
    54. _targetClass = new CodeTypeDeclaration(className);
    55. _targetClass.IsClass = true;
    56. _targetClass.TypeAttributes = visitAttr;
    57. _samples.Types.Add(_targetClass);
    58. _targetUnit.Namespaces.Add(_samples);
    59. NameSpace = nameSpace;
    60. ClassName = className;
    61. FullNameSpaceWithClass = NameSpace + "." + ClassName;
    62. _outputFileName = fileFullPath;
    63. #endregion
    64. if (AfterConstructor != null)
    65. {
    66. AfterConstructor();
    67. }
    68. }
    69. #endregion

    其实写了半天主要就是最后一个,剩下的我都自动默认了。
    默认构造函数可空,那里留了个Action,那是用来做扩展的,咱们最后再说,不过如果你踏踏实实的看下来了,应该也猜个差不多了。
    剩下的就是初始化一些内容,如果你不填你创建的这个对象类名,命名空间啥的,我就随便给你写一份。反正你也不关心
    你只需要记住,在你new的时候,我会先触发一次且仅一次的callback给你做扩展,至于扩展啥,我也不知道。
    然后开始了构建构造函数和基本的对象实例等等啥的。
    在这里有2个时间点可以扩展,分别是构造前和构造后,2个callback
    然后没啥好说的了
    ==========================================白活线====================================================
    下面看怎么加命名空间

    1. #region NameSpaceAdded Function Area
    2. /// <summary>
    3. /// 新增命名空间
    4. /// </summary>
    5. /// <param name="codeNamespaceImport">命名空间文本,不需要添加using</param>
    6. public CodeMacker AddNamespace(string codeNamespaceImport)
    7. => AddNamespaces(() => new List<CodeNamespaceImport> { new CodeNamespaceImport(codeNamespaceImport) });
    8. /// <summary>
    9. /// 新增多个命名空间
    10. /// </summary>
    11. /// <param name="codeNamespaceImport">命名空间文本,不需要添加using</param>
    12. public CodeMacker AddNamespaces(List<string> codeNamespaceImport)
    13. {
    14. List<CodeNamespaceImport> codeNamespace = new List<CodeNamespaceImport>();
    15. codeNamespaceImport.ForEach(c => codeNamespace.Add(new CodeNamespaceImport(c)));
    16. return AddNamespaces(() => codeNamespace);
    17. }
    18. /// <summary>
    19. /// 新增命名空间 自定义
    20. ///
    21. /// Demo
    22. /// var codeNamespace = new CodeNamespaceImport>("namespace");
    23. /// </summary>
    24. /// <param name="codeNamespaceImport"></param>
    25. public CodeMacker AddNamespace(Func<CodeNamespaceImport> codeNamespaceImport)
    26. => AddNamespaces(() => new List<CodeNamespaceImport> { codeNamespaceImport() });
    27. /// <summary>
    28. /// 新增命名空间 自定义
    29. ///
    30. /// Demo
    31. /// var codeNamespace = new List<CodeNamespaceImport>()
    32. /// {
    33. /// new CodeNamespaceImport("namespace")
    34. /// };
    35. /// </summary>
    36. /// <param name="codeNamespaceImport"></param>
    37. public CodeMacker AddNamespaces(Func<List<CodeNamespaceImport>> codeNamespaceImport)
    38. {
    39. if (BeforeAddNamespace != null)
    40. {
    41. BeforeAddNamespace();
    42. }
    43. codeNamespaceImport().ForEach(c => _samples.Imports.Add(c));
    44. if (AfterAddNamespace != null)
    45. {
    46. AfterAddNamespace();
    47. }
    48. return this;
    49. }
    50. #endregion

    这里,就是你引用包的一些地方,比如你这个类要引用一些个命名空间,就这玩意儿,用的时候不用加using
    image.png
    调用很简单,就是直接传字符串,多的话扔个List
    怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback
    写Fun的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。
    ==========================================白活线====================================================
    然后是构造函数,这里的构造函数是指的构造你这个生成对象的构造函数,不是构造这个类的方法

    1. #region Constructor Function Area
    2. /// <summary>
    3. /// 添加构造函数
    4. /// </summary>
    5. /// <param name="ctor">ctor</param>
    6. public CodeMacker AddConstructor(ConstructorEntity ctor)
    7. => AddConstructor(
    8. () =>
    9. {
    10. if (ctor is null)
    11. {
    12. throw new ArgumentException("构造函数基本访问类型参数不能为空");
    13. }
    14. // Declare the constructor
    15. CodeConstructor constructor = new CodeConstructor();
    16. constructor.Attributes = ctor.Attr;
    17. if (ctor.Params != null)
    18. {
    19. ctor.Params.ForEach(s =>
    20. {
    21. // Add parameters.
    22. constructor.Parameters.Add(new CodeParameterDeclarationExpression(
    23. s.ParamType, s.Name));
    24. if (!string.IsNullOrEmpty(s.ReferenceName))
    25. {
    26. // Add field initialization logic
    27. CodeFieldReferenceExpression reference =
    28. new CodeFieldReferenceExpression(
    29. new CodeThisReferenceExpression(), s.ReferenceName);
    30. constructor.Statements.Add(new CodeAssignStatement(reference,
    31. new CodeArgumentReferenceExpression(s.Name)));
    32. }
    33. });
    34. }
    35. return constructor;
    36. });
    37. /// <summary>
    38. /// 添加构造函数
    39. /// </summary>
    40. /// <param name="ctor">ctor</param>
    41. public CodeMacker AddConstructor(Func<CodeConstructor> ctor)
    42. {
    43. if (BeforeAddConstructor != null)
    44. {
    45. BeforeAddConstructor();
    46. }
    47. _targetClass.Members.Add(ctor());
    48. if (AfterAddConstructor != null)
    49. {
    50. AfterAddConstructor();
    51. }
    52. return this;
    53. }
    54. #endregion

    怎么传参,New就可以了。比如你的构造函数要public A(int a,intb){}
    那就看上一篇里面那个Entity的定义就好,吧参数对应写进去,参数名称,参数类型,给哪个参数赋值。
    如果你构造函数不用默认参数,那写这个干啥,默认就是隐藏无参构造函数的。

    怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback
    写Fun的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。
    ==========================================白活线====================================================
    然后是字段了

    1. #region Field Function Area
    2. /// <summary>
    3. /// 新增字段
    4. /// </summary>
    5. /// <param name="FieldEntity">字段Model</param>
    6. public CodeMacker AddField(FieldEntity fieldModel)
    7. => AddField(() =>
    8. {
    9. if (fieldModel is null)
    10. {
    11. throw new ArgumentException("字段参数信息不能为null");
    12. }
    13. return GetFieldBy(fieldModel);
    14. });
    15. /// <summary>
    16. /// 新增多个字段
    17. /// </summary>
    18. /// <param name="FieldEntity">字段Model</param>
    19. public CodeMacker AddFields(List<FieldEntity> fields)
    20. {
    21. fields.ForEach(f => AddField(f));
    22. return this;
    23. }
    24. /// <summary>
    25. /// 新增字段
    26. /// </summary>
    27. /// <param name="attr">字段标签</param>
    28. /// <param name="fieldName">字段名称</param>
    29. /// <param name="fieldType">字段类型</param>
    30. /// <param name="comment">字段注释</param>
    31. public CodeMacker AddField(MemberAttributes attr, string fieldName, Type fieldType, object defaultValue = default, string comment = null)
    32. => AddField(
    33. new FieldEntity(fieldName, fieldType)
    34. {
    35. Attr = attr,
    36. Comment = comment,
    37. DefaultValue = defaultValue,
    38. });
    39. /// <summary>
    40. /// 新增字段(自定义)
    41. ///
    42. /// 示例:
    43. /// CodeMemberField field = new CodeMemberField();
    44. /// field.Attributes = attr;
    45. /// field.Name = fieldName;
    46. /// field.Type = new CodeTypeReference(fieldType);
    47. /// if (!string.IsNullOrEmpty(comment))
    48. /// {
    49. /// field.Comments.Add(new CodeCommentStatement(comment));
    50. /// }
    51. /// return field;
    52. /// </summary>
    53. /// <param name="fieldMember">字段类型</param>
    54. public CodeMacker AddField(Func<CodeMemberField> fieldMember)
    55. => AddFields(() => new List<CodeMemberField> { fieldMember() });
    56. /// <summary>
    57. /// 新增多个字段(自定义)
    58. ///
    59. ///
    60. /// Demo:
    61. /// List<CodeMemberField> fields = new List<CodeMemberField>();
    62. /// CodeMemberField field = new CodeMemberField();
    63. /// field.Attributes = attr;
    64. /// field.Name = fieldName;
    65. /// field.Type = new CodeTypeReference(fieldType);
    66. /// if (!string.IsNullOrEmpty(comment))
    67. /// {
    68. /// field.Comments.Add(new CodeCommentStatement(comment));
    69. /// }
    70. /// fields.Add(field);
    71. /// return fields;
    72. ///
    73. /// </summary>
    74. /// <param name="fieldMember"></param>
    75. public CodeMacker AddFields(Func<List<CodeMemberField>> fieldMember)
    76. {
    77. if (BeforeAddField != null)
    78. {
    79. BeforeAddField();
    80. }
    81. fieldMember().ForEach(f => _targetClass.Members.Add(f));
    82. if (AfterAddField != null)
    83. {
    84. AfterAddField();
    85. }
    86. return this;
    87. }
    88. private CodeMemberField GetFieldBy(FieldEntity fieldModel)
    89. {
    90. // Declare the Value field.
    91. CodeMemberField field = new CodeMemberField(new CodeTypeReference(fieldModel.Type), fieldModel.Name);
    92. field.Attributes = fieldModel.Attr;
    93. if (fieldModel.DefaultValue != null)
    94. {
    95. field.InitExpression = new CodePrimitiveExpression(fieldModel.DefaultValue);
    96. }
    97. if (!string.IsNullOrEmpty(fieldModel.Comment))
    98. {
    99. field.Comments.Add(new CodeCommentStatement(fieldModel.Comment));
    100. }
    101. return field;
    102. }
    103. #endregion

    字段就是把对象New进去,或者直接写参数,有留出来的一个方法,其实底下我也是自己new了一个,没啥区别,看使用习惯。
    new的时候强制你要写名称和类型,都定好了,不写不行你,这个也没啥好说的,比较简单

    怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback
    写Fun的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。
    ==========================================白活线====================================================
    然后是属性了,属性稍微有点东西讲一点

    1. #region Properties Function Area
    2. /// <summary>
    3. /// 新增属性
    4. /// </summary>
    5. /// <param name="pro">属性Model</param>
    6. public CodeMacker AddPropertie(PropertyEntity pro)
    7. => AddProperties(() =>
    8. {
    9. if (pro is null)
    10. {
    11. throw new ArgumentException("属性参数信息不能为null");
    12. }
    13. // Declare the read-only Width property.
    14. string fieldName = string.Empty;
    15. if (pro.HasGet && pro.HasSet)
    16. {
    17. fieldName = pro.Name + " { get; set; }//";
    18. }
    19. else if (pro.HasGet && !pro.HasSet)
    20. {
    21. fieldName = pro.Name + " { get; }//";
    22. }
    23. else
    24. {
    25. throw new ArgumentException("属性不能设置只写或当成字段来使用");
    26. }
    27. var propertity = GetFieldBy(new FieldEntity(fieldName, pro.Type)
    28. {
    29. Attr = pro.Attr,
    30. Comment = pro.Comment
    31. });
    32. return new List<CodeTypeMember> { propertity };
    33. });
    34. /// <summary>
    35. /// 增加属性
    36. /// </summary>
    37. /// <param name="attr">属性标签</param>
    38. /// <param name="propertieName">属性名称</param>
    39. /// <param name="propertieType">属性类型</param>
    40. /// <param name="comment">属性注释</param>
    41. public CodeMacker AddPropertie(MemberAttributes attr, string propertieName, Type propertieType, string comment = null)
    42. => AddPropertie(new PropertyEntity(propertieName, propertieType)
    43. {
    44. HasGet = true,
    45. HasSet = true,
    46. Comment = comment
    47. });
    48. /// <summary>
    49. /// 添加多个属性
    50. /// </summary>
    51. /// <param name="pros"></param>
    52. public CodeMacker AddProperties(List<PropertyEntity> pros)
    53. {
    54. pros.ForEach(s => AddPropertie(s));
    55. return this;
    56. }
    57. /// <summary>
    58. /// 新增1个属性(自定义)
    59. /// </summary>
    60. /// <param name="propertyMember">Func CodeTypeMember</param>
    61. public CodeMacker AddPropertie(Func<CodeTypeMember> propertyMember)
    62. => AddProperties(() => new List<CodeTypeMember>
    63. {
    64. propertyMember()
    65. }
    66. );
    67. /// <summary>
    68. /// 新增多个属性(自定义)
    69. /// </summary>
    70. /// <param name="propertyMember">Func list CodeTypeMember</param>
    71. public CodeMacker AddProperties(Func<List<CodeTypeMember>> propertyMember)
    72. {
    73. if (BeforeAddPropertie != null)
    74. {
    75. BeforeAddPropertie();
    76. }
    77. propertyMember().ForEach(p => _targetClass.Members.Add(p));
    78. if (AfterAddPropertie != null)
    79. {
    80. AfterAddPropertie();
    81. }
    82. return this;
    83. }
    84. #endregion

    如果你,如果哈,如果你认真的看了方法,你就会发现,我特|么的不是还是字段吗,没错。就是这样
    官方给的默认方法是这样的,如果是生成的属性,没有自动属性,必须得在get和set里写逻辑,但是说白了大多时候我们不需要这么做(懒)
    所以就写个自动属性,但是问题在于官方没有给自动属性的操作方式。
    在第一章里我说过,CodeDom本身是生成个字符串,所以费那脑子干嘛,
    字段加点料,不就行了?(我才不会说我也是查到的,啊哈哈哈哈)
    其他没有区别了,加多个,单个都可以。如果你有写get,set逻辑的需求,那就去调用func自己写。
    但是需要你自己去学习CodeDom那些弯弯道道了,我反正是懒得写了。

    怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback
    写Fun的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。
    ==========================================白活线====================================================
    这里该说方法了,方法,很重要的一环。但是,异常简单。甚至没什么好说的。

    1. #region Method Area
    2. /// <summary>
    3. /// 添加方法
    4. /// </summary>
    5. /// <param name="methods">方法</param>
    6. /// <returns>this</returns>
    7. public CodeMacker AddMethod(string method, string comment = null)
    8. => AddMethod(new MethodEntity { Method = method, Comment = comment });
    9. /// <summary>
    10. /// 添加单个方法
    11. /// </summary>
    12. /// <param name="methods">方法</param>
    13. /// <returns>this</returns>
    14. public CodeMacker AddMethod(MethodEntity method)
    15. => AddMethods(new List<MethodEntity> { method });
    16. /// <summary>
    17. /// 添加多个方法
    18. /// </summary>
    19. /// <param name="methods">方法集合</param>
    20. /// <returns>this</returns>
    21. public CodeMacker AddMethods(List<MethodEntity> methods)
    22. => AddMethods(() =>
    23. {
    24. var methodsList = new List<CodeTypeMember>();
    25. methods.ForEach(m =>
    26. {
    27. CodeSnippetTypeMember snippet = new CodeSnippetTypeMember
    28. {
    29. Text = m.Method
    30. };
    31. if (!string.IsNullOrEmpty(m.Comment))
    32. {
    33. snippet.Comments.Add(new CodeCommentStatement(m.Comment, false));
    34. }
    35. methodsList.Add(snippet);
    36. });
    37. return methodsList;
    38. });
    39. /// <summary>
    40. /// 添加方法(自定义)
    41. /// </summary>
    42. /// <param name="method">Func<CodeTypeMember></param>
    43. public CodeMacker AddMethod(Func<CodeTypeMember> method)
    44. => AddMethods(() => new List<CodeTypeMember> { method() });
    45. /// <summary>
    46. /// 添加多个方法(自定义)
    47. /// </summary>
    48. /// <param name="method">Func<List<CodeTypeMember>></param>
    49. public CodeMacker AddMethods(Func<List<CodeTypeMember>> method)
    50. {
    51. if (BeforeAddMethod != null)
    52. {
    53. BeforeAddMethod();
    54. }
    55. method().ForEach(m => _targetClass.Members.Add(m));
    56. if (AfterAddMethod != null)
    57. {
    58. AfterAddMethod();
    59. }
    60. return this;
    61. }
    62. #endregion

    其实看了这么多,你会发现,我写的代码都差不多,圈套圈的。实现就那一个。
    本来方法是很复杂的一个内容,里面可能要写for,if,while,event,action ,obj…..
    官方给的逻辑非常之复杂
    复杂到我不想学了,但是,但是,但是我找到了一个非常简单的方法,那就是,你给我把方法传个字符串进来,我给你生成。
    没错,就是字面意思。传个字符串。具体怎么用,后面有示例。
    如果你有自定义生成的需求,那就调用Fun的方法吧,自定义就可以。但是很麻烦。

    怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback
    写Fun的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。
    ==========================================白活线====================================================
    ok。到此为止,基本上都有了,命名空间,类,字段,属性,方法都齐活儿了。
    那就应该是输出了对吧,。
    来,我们看输出。

    1. #region OutPut
    2. /// <summary>
    3. /// 控制台输出
    4. /// </summary>
    5. /// <returns></returns>
    6. public CodeMacker Log()
    7. {
    8. CodeDomProvider prvd = CodeDomProvider.CreateProvider("cs");
    9. prvd.GenerateCodeFromCompileUnit(_targetUnit, Console.Out, null);
    10. return this;
    11. }
    12. /// <summary>
    13. /// 文本输出(string)
    14. /// </summary>
    15. /// <param name="fileFullPath">文件地址</param>
    16. public string GenerateCSharpString()
    17. => CodeDomOutString(() =>
    18. {
    19. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
    20. CodeGeneratorOptions options = new CodeGeneratorOptions { BracingStyle = "C" };
    21. using (StringWriter sourceWriter = new StringWriter())
    22. {
    23. provider.GenerateCodeFromCompileUnit(_targetUnit, sourceWriter, options);
    24. return sourceWriter.ToString();
    25. }
    26. });
    27. /// <summary>
    28. /// 自定义CodeDom输出(string)
    29. /// </summary>
    30. /// <param name="fileFullPath">文件地址</param>
    31. public string CodeDomOutString(Func<string> codeDomContext)
    32. => codeDomContext();
    33. /// <summary>
    34. /// 文件输出(.cs)
    35. /// </summary>
    36. /// <param name="fileFullPath">文件地址</param>
    37. public CodeMacker GenerateCSharpFile(string fileFullPath)
    38. {
    39. if (string.IsNullOrEmpty(fileFullPath))
    40. {
    41. throw new ArgumentException("文件输出路径为空,请设置输出路径!");
    42. }
    43. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
    44. CodeGeneratorOptions options = new CodeGeneratorOptions();
    45. options.BracingStyle = "C";
    46. using (StreamWriter sourceWriter = new StreamWriter(fileFullPath))
    47. {
    48. provider.GenerateCodeFromCompileUnit(
    49. _targetUnit, sourceWriter, options);
    50. }
    51. return this;
    52. }
    53. /// <summary>
    54. /// 文件输出(.cs)
    55. /// </summary>
    56. public CodeMacker CodeDomOutFile()
    57. => GenerateCSharpFile(_outputFileName);
    58. #endregion

    第一个是控制台输出,调试的时候用这个,能直接看到生成的对象类。
    第二个是文本输出,也就是我们的核心方法,生成对象全靠它
    第三个是自定义输出,你自己爱怎么玩怎么玩。
    第四个是文件输出,如果你碰到生成对象后怎么调用也无法成功的时候,记住,输出个文本,你会找到问题的。v1=🤞😁😁😁
    最后一个略过

    怎么用就不说了,这里没有时间节点扩展,别找了。
    写Fun的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。
    ==========================================白活线====================================================
    重头戏来了,怎么生成对象呢,就在这里
    看代码先

    1. #region CreateInstance Function Area
    2. /// <summary>
    3. /// 创建单例对象 按命名空间+类名区分
    4. /// </summary>
    5. /// <returns></returns>
    6. public object CreateInstanceOfSingleton()
    7. => CreateInstanceOfSingleton(this.GenerateCSharpString(), this.FullNameSpaceWithClass);
    8. /// <summary>
    9. /// 创建单例对象 按命名空间+类名区分
    10. /// </summary>
    11. /// <param name="context">创建对象文本</param>
    12. /// <param name="fullNamespaceClass">命名空间+类名称</param>
    13. /// <returns></returns>
    14. public object CreateInstanceOfSingleton(string context, string fullNamespaceClass)
    15. {
    16. if (HasSingletonInstance(fullNamespaceClass))
    17. {
    18. return GetSingletonInstanceBy(fullNamespaceClass);
    19. }
    20. var instance = CreateInstance(context, fullNamespaceClass);
    21. _singletonContainer.Add(fullNamespaceClass, instance);
    22. return instance;
    23. }
    24. /// <summary>
    25. /// 根据本类构建对象
    26. /// </summary>
    27. /// <returns>返回Object类,根据内容反射获取信息</returns>
    28. public object CreateInstance()
    29. => CreateInstance(this.GenerateCSharpString(), this.FullNameSpaceWithClass);
    30. /// <summary>
    31. /// 根据传入内容构建对象
    32. /// </summary>
    33. /// <returns>返回Object类,根据内容反射获取信息</returns>
    34. public object CreateInstance(string context, string fullNamespaceClass)
    35. => CreateInstance(() =>
    36. {
    37. #region Verify
    38. if (string.IsNullOrEmpty(context))
    39. {
    40. throw new ArgumentException("生成的代码不能为空");
    41. }
    42. if (string.IsNullOrEmpty(fullNamespaceClass))
    43. {
    44. throw new ArgumentException("命名空间和类名称不能为空");
    45. }
    46. #endregion
    47. #region 加载构建
    48. var refPaths = new[]
    49. {
    50. typeof(System.Object).GetTypeInfo().Assembly.Location,
    51. typeof(Console).GetTypeInfo().Assembly.Location,
    52. Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll")
    53. };
    54. MetadataReference[] references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray();
    55. CSharpCompilation compilation = CSharpCompilation.Create(
    56. Path.GetRandomFileName(),
    57. syntaxTrees: new[] { CSharpSyntaxTree.ParseText(context) },
    58. references: references,
    59. options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
    60. #endregion
    61. #region 创建对象
    62. using (var ms = new MemoryStream())
    63. {
    64. EmitResult result = compilation.Emit(ms);
    65. if (result.Success)
    66. {
    67. ms.Seek(0, SeekOrigin.Begin);
    68. Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
    69. //var type = assembly.GetType("CodeDOM.CodeDOMCreatedClass");
    70. return assembly.CreateInstance(fullNamespaceClass);
    71. }
    72. else
    73. {
    74. return result.Diagnostics.Where(diagnostic =>
    75. diagnostic.IsWarningAsError ||
    76. diagnostic.Severity == DiagnosticSeverity.Error);
    77. }
    78. }
    79. #endregion
    80. });
    81. /// <summary>
    82. /// 构建自定义生成方式和对象
    83. /// </summary>
    84. /// <returns>返回Object类,根据内容反射获取信息</returns>
    85. public object CreateInstance(Func<object> createInfo)
    86. {
    87. if (BeforeCreateInstance != null)
    88. {
    89. BeforeCreateInstance();
    90. }
    91. var resultObj = createInfo();
    92. if (AfterCreateInstance != null)
    93. {
    94. AfterCreateInstance();
    95. }
    96. return resultObj;
    97. }
    98. #endregion
    99. #region Singleton Ioc Function Area
    100. /// <summary>
    101. /// 获取单例对象
    102. /// </summary>
    103. /// <param name="key">命名空间+类名称</param>
    104. /// <returns></returns>
    105. public static object GetSingletonInstanceBy(string key)
    106. => HasSingletonInstance(key) ? _singletonContainer[key] : null;
    107. /// <summary>
    108. /// 是否包含单例对象
    109. /// </summary>
    110. /// <param name="key">命名空间+类名称</param>
    111. /// <returns></returns>
    112. public static bool HasSingletonInstance(string key)
    113. => _singletonContainer.ContainsKey(key);
    114. #endregion

    这里我做了两套,一套是单例,一套是瞬时(普通new)至于为什么没有Scope,因为我没有Scope的作用域呀,啊哈哈哈哈啊
    单例的方法是在最上面,有一个字典

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

    从这里存取。
    重点说生成实例方法。
    CodeDom在FrameWork的时代里面是支持直接生成对象的,但是如果在NetCore或者Net5当中是不支持直接生成,会报平台错误,具体怎么我就不演示了
    没有意义,如果你是FrameWork使用的话,可以找一找代码,那个很简单,几行。
    我这里是用了Emit来进行操作,怎么个逻辑调用跑来跑去的就那一堆,我看了半天也懒得分析了,直接用吧,还挺好。性能,算了,这里我们不说性能,如果有好的意见也可以提出来,我看心情改,啊哈哈哈哈哈
    这里就是把字符串传进去,然后生成对象,就这样。多余的内容我封装好了。
    单例默认用命名空间+类来作为Key,你自定义也可以,传给我

    怎么用就不说了,这里也有2个时间点可以扩展,分别是开始前和增加后,2个callback
    写Fun的是留出来的扩展,如果你本身很了解CodeDom可以直接自己写内容使用。
    ==========================================白活线====================================================
    最后我们来看一下所有的时间节点。

    1. #region CodeMaker Filter 节点
    2. private static bool _onecEventNotRun = true;
    3. /// <summary>
    4. /// 整个项目运行中只调用一次的事件,事件发生点在尚未构造对象之前
    5. /// </summary>
    6. public event Action DoOnceWorkBeforeConstructor = null;
    7. /// <summary>
    8. /// 开始构造函数之前
    9. /// </summary>
    10. public event Action BeforeConstructor = null;
    11. /// <summary>
    12. /// 结束构造函数时
    13. /// </summary>
    14. public event Action AfterConstructor = null;
    15. /// <summary>
    16. /// 添加命名空间之前(生成代码 AddNamespace)
    17. /// </summary>
    18. public event Action BeforeAddNamespace = null;
    19. /// <summary>
    20. /// 添加命名空间之后(生成代码 AddNamespace)
    21. /// </summary>
    22. public event Action AfterAddNamespace = null;
    23. /// <summary>
    24. /// 添加构造函数之前(生成代码 AddConstructor)
    25. /// </summary>
    26. public event Action BeforeAddConstructor = null;
    27. /// <summary>
    28. /// 添加构造函数之后(生成代码 AddConstructor)
    29. /// </summary>
    30. public event Action AfterAddConstructor = null;
    31. /// <summary>
    32. /// 添加字段之前(生成代码 AddField)
    33. /// </summary>
    34. public event Action BeforeAddField = null;
    35. /// <summary>
    36. /// 添加字段之后(生成代码 AddField)
    37. /// </summary>
    38. public event Action AfterAddField = null;
    39. /// <summary>
    40. /// 添加属性之前(生成代码 AddPropertie)
    41. /// </summary>
    42. public event Action BeforeAddPropertie = null;
    43. /// <summary>
    44. /// 添加属性之后(生成代码 AddPropertie)
    45. /// </summary>
    46. public event Action AfterAddPropertie = null;
    47. /// <summary>
    48. /// 添加方法之前(生成代码 AddMethod)
    49. /// </summary>
    50. public event Action BeforeAddMethod = null;
    51. /// <summary>
    52. /// 添加方法之后(生成代码 AddMethod)
    53. /// </summary>
    54. public event Action AfterAddMethod = null;
    55. /// <summary>
    56. /// 创建对象之前(生成实例 CreateInstance)
    57. /// </summary>
    58. public event Action BeforeCreateInstance = null;
    59. /// <summary>
    60. /// 创建对象之后(生成实例 CreateInstance)
    61. /// </summary>
    62. public event Action AfterCreateInstance = null;
    63. #endregion

    嗯,没什么好说的,在构造函数里初始化赋值就可以了。
    好了,你们期待的Demo示例这里我不打算写了,因为我写累了。下一章里写,具体名字叫啥呢,就是CodeDom的完结吧,啊哈哈哈哈哈(恶习多多)
    ————————————————
    原文链接:https://www.cnblogs.com/SevenWang/p/15568399.html