Newer
Older
DungeonShooting / DungeonShooting_Godot / excelTool / ExcelGenerator.cs
@小李xl 小李xl on 15 Mar 2024 32 KB buff系统重构中
  1.  
  2. using System.Text.Json;
  3. using System.Text.RegularExpressions;
  4. using Aspose.Cells;
  5. using Environment = System.Environment;
  6.  
  7. public static class ExcelGenerator
  8. {
  9. private static HashSet<string> _excelNames = new HashSet<string>();
  10. private enum CollectionsType
  11. {
  12. None,
  13. Array,
  14. Map
  15. }
  16. private class MappingData
  17. {
  18. public string TypeStr;
  19. public string TypeName;
  20. public CollectionsType CollectionsType;
  21. public bool AutoParentheses = false;
  22. public bool IsRefExcel;
  23. public string RefTypeStr;
  24. public string RefTypeName;
  25.  
  26. public MappingData(string typeStr, string typeName, CollectionsType collectionsType)
  27. {
  28. TypeStr = typeStr;
  29. TypeName = typeName;
  30. CollectionsType = collectionsType;
  31. IsRefExcel = false;
  32. }
  33. public MappingData(string typeStr, string typeName, CollectionsType collectionsType, string refTypeStr, string refTypeName)
  34. {
  35. TypeStr = typeStr;
  36. TypeName = typeName;
  37. CollectionsType = collectionsType;
  38. IsRefExcel = true;
  39. RefTypeStr = refTypeStr;
  40. RefTypeName = refTypeName;
  41. }
  42. }
  43.  
  44. private class ExcelData
  45. {
  46. public string TableName;
  47. public string OutCode;
  48. public List<string> ColumnNames = new List<string>();
  49. public Dictionary<string, MappingData> ColumnMappingData = new Dictionary<string, MappingData>();
  50. public Dictionary<string, Type> ColumnType = new Dictionary<string, Type>();
  51. public List<Dictionary<string, object>> DataList = new List<Dictionary<string, object>>();
  52. }
  53. /// <summary>
  54. /// 导出 Excel 表
  55. /// </summary>
  56. public static bool ExportExcel()
  57. {
  58. var excelPath = "excel/";
  59. var jsonPath = "config/";
  60. var codePath = "src/";
  61. return ExportExcel(excelPath, jsonPath, codePath);
  62. }
  63. /// <summary>
  64. /// 导出 Excel 表
  65. /// </summary>
  66. /// <param name="excelFilePath">excel文件路径</param>
  67. /// <param name="jsonOutPath">json配置输出路径</param>
  68. /// <param name="codeOutPath">代码输出路径</param>
  69. public static bool ExportExcel(string excelFilePath, string jsonOutPath, string codeOutPath)
  70. {
  71. _excelNames.Clear();
  72. Console.WriteLine("当前路径: " + Environment.CurrentDirectory);
  73. Console.WriteLine("excel路径: " + excelFilePath);
  74. Console.WriteLine("json输出路径: " + jsonOutPath);
  75. Console.WriteLine("cs代码输出路径: " + codeOutPath);
  76. try
  77. {
  78. var excelDataList = new List<ExcelData>();
  79. var directoryInfo = new DirectoryInfo(excelFilePath);
  80. if (directoryInfo.Exists)
  81. {
  82. var fileInfos = directoryInfo.GetFiles();
  83. //记录文件
  84. foreach (var fileInfo in fileInfos)
  85. {
  86. if (fileInfo.Extension == ".xlsx")
  87. {
  88. var fileName = Path.GetFileNameWithoutExtension(fileInfo.Name).FirstToUpper();
  89. _excelNames.Add(fileName);
  90. }
  91. }
  92.  
  93. //读取配置文件
  94. foreach (var fileInfo in fileInfos)
  95. {
  96. if (fileInfo.Extension == ".xlsx")
  97. {
  98. if (fileInfo.Name == "ExcelConfig.xlsx")
  99. {
  100. throw new Exception("excel表文件名称不允许叫'ExcelConfig.xlsx'!");
  101. }
  102. Console.WriteLine("excel表: " + fileInfo.FullName);
  103. excelDataList.Add(ReadExcel(fileInfo.FullName));
  104. }
  105. }
  106. }
  107.  
  108. Console.WriteLine($"一共检测到excel表共{excelDataList.Count}张.");
  109. if (excelDataList.Count == 0)
  110. {
  111. return true;
  112. }
  113. if (Directory.Exists(codeOutPath))
  114. {
  115. Directory.Delete(codeOutPath, true);
  116. }
  117. if (Directory.Exists(jsonOutPath))
  118. {
  119. Directory.Delete(jsonOutPath, true);
  120. }
  121. Directory.CreateDirectory(codeOutPath);
  122. Directory.CreateDirectory(jsonOutPath);
  123. //保存配置和代码
  124. foreach (var excelData in excelDataList)
  125. {
  126. File.WriteAllText(codeOutPath + "ExcelConfig_" + excelData.TableName + ".cs", excelData.OutCode);
  127. var config = new JsonSerializerOptions();
  128. config.WriteIndented = true;
  129. File.WriteAllText(jsonOutPath + excelData.TableName + ".json", JsonSerializer.Serialize(excelData.DataList, config));
  130. }
  131. //生成加载代码
  132. var code = GeneratorInitCode(excelDataList);
  133. File.WriteAllText(codeOutPath + "ExcelConfig.cs", code);
  134. }
  135. catch (Exception e)
  136. {
  137. PrintError(e.ToString());
  138. return false;
  139. }
  140.  
  141. return true;
  142. }
  143.  
  144. private static string GeneratorInitCode(List<ExcelData> excelList)
  145. {
  146. var code = $"using System;\n";
  147. code += $"using System.Collections.Generic;\n";
  148. code += $"using System.Text.Json;\n";
  149. code += $"using Godot;\n";
  150. code += $"\n";
  151. code += $"namespace Config;\n";
  152. code += $"\n";
  153. code += $"public static partial class ExcelConfig\n";
  154. code += $"{{\n";
  155.  
  156. var fieldCode = "";
  157. var callFuncCode = "";
  158. var callInitRefFuncCode = "";
  159. var funcCode = "";
  160. var initRefFuncCode = "";
  161. foreach (var excelData in excelList)
  162. {
  163. var idName = excelData.ColumnNames[0];
  164. var idTypeStr = excelData.ColumnMappingData[idName].TypeStr;
  165. //---------------------------- 引用其他表处理 ----------------------------
  166. var hasRefColumn = false;
  167. var refColumnNoneCode = "";
  168. foreach (var columnName in excelData.ColumnNames)
  169. {
  170. var mappingData = excelData.ColumnMappingData[columnName];
  171. if (mappingData.IsRefExcel)
  172. {
  173. hasRefColumn = true;
  174. if (mappingData.CollectionsType == CollectionsType.None)
  175. {
  176. refColumnNoneCode += $" if (!string.IsNullOrEmpty(item.__{columnName}))\n";
  177. refColumnNoneCode += $" {{\n";
  178. refColumnNoneCode += $" item.{columnName} = {mappingData.RefTypeName}_Map[item.__{columnName}];\n";
  179. refColumnNoneCode += $" }}\n";
  180. }
  181. else if (mappingData.CollectionsType == CollectionsType.Array)
  182. {
  183. refColumnNoneCode += $" if (item.__{columnName} != null)\n";
  184. refColumnNoneCode += $" {{\n";
  185. refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeName}[item.__{columnName}.Length];\n";
  186. refColumnNoneCode += $" for (var i = 0; i < item.__{columnName}.Length; i++)\n";
  187. refColumnNoneCode += $" {{\n";
  188. refColumnNoneCode += $" item.{columnName}[i] = {mappingData.RefTypeName}_Map[item.__{columnName}[i]];\n";
  189. refColumnNoneCode += $" }}\n";
  190. refColumnNoneCode += $" }}\n";
  191. }
  192. else
  193. {
  194. refColumnNoneCode += $" if (item.__{columnName} != null)\n";
  195. refColumnNoneCode += $" {{\n";
  196. refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeStr}();\n";
  197. refColumnNoneCode += $" foreach (var pair in item.__{columnName})\n";
  198. refColumnNoneCode += $" {{\n";
  199. refColumnNoneCode += $" item.{columnName}.Add(pair.Key, {mappingData.RefTypeName}_Map[pair.Value]);\n";
  200. refColumnNoneCode += $" }}\n";
  201. refColumnNoneCode += $" }}\n";
  202. }
  203. refColumnNoneCode += $"\n";
  204. }
  205. }
  206. //----------------------------- 数据集合 ------------------------------------
  207. fieldCode += $" /// <summary>\n";
  208. fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 以 List 形式存储, 数据顺序与 Excel 表相同\n";
  209. fieldCode += $" /// </summary>\n";
  210. fieldCode += $" public static List<{excelData.TableName}> {excelData.TableName}_List {{ get; private set; }}\n";
  211. fieldCode += $" /// <summary>\n";
  212. fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 里 Map 形式存储, key 为 {idName}\n";
  213. fieldCode += $" /// </summary>\n";
  214. fieldCode += $" public static Dictionary<{idTypeStr}, {excelData.TableName}> {excelData.TableName}_Map {{ get; private set; }}\n";
  215. fieldCode += $"\n";
  216. //------------------------------- 初始化函数 -------------------------------------
  217. callFuncCode += $" _Init{excelData.TableName}Config();\n";
  218. funcCode += $" private static void _Init{excelData.TableName}Config()\n";
  219. funcCode += $" {{\n";
  220. funcCode += $" try\n";
  221. funcCode += $" {{\n";
  222. funcCode += $" var text = _ReadConfigAsText(\"res://resource/config/{excelData.TableName}.json\");\n";
  223. if (hasRefColumn) //存在引用列
  224. {
  225. funcCode += $" {excelData.TableName}_List = new List<{excelData.TableName}>(JsonSerializer.Deserialize<List<Ref_{excelData.TableName}>>(text));\n";
  226. }
  227. else
  228. {
  229. funcCode += $" {excelData.TableName}_List = JsonSerializer.Deserialize<List<{excelData.TableName}>>(text);\n";
  230. }
  231. funcCode += $" {excelData.TableName}_Map = new Dictionary<{idTypeStr}, {excelData.TableName}>();\n";
  232. funcCode += $" foreach (var item in {excelData.TableName}_List)\n";
  233. funcCode += $" {{\n";
  234. funcCode += $" {excelData.TableName}_Map.Add(item.{idName}, item);\n";
  235. funcCode += $" }}\n";
  236. funcCode += $" }}\n";
  237. funcCode += $" catch (Exception e)\n";
  238. funcCode += $" {{\n";
  239. funcCode += $" GD.PrintErr(e.ToString());\n";
  240. funcCode += $" throw new Exception(\"初始化表'{excelData.TableName}'失败!\");\n";
  241. funcCode += $" }}\n";
  242. funcCode += $" }}\n";
  243.  
  244. //------------------------------- 初始化引用 ---------------------------------
  245. if (hasRefColumn)
  246. {
  247. callInitRefFuncCode += $" _Init{excelData.TableName}Ref();\n";
  248.  
  249. initRefFuncCode += $" private static void _Init{excelData.TableName}Ref()\n";
  250. initRefFuncCode += $" {{\n";
  251. initRefFuncCode += $" foreach (Ref_{excelData.TableName} item in {excelData.TableName}_List)\n";
  252. initRefFuncCode += $" {{\n";
  253. initRefFuncCode += $" try\n";
  254. initRefFuncCode += $" {{\n";
  255. initRefFuncCode += refColumnNoneCode;
  256. initRefFuncCode += $" }}\n";
  257. initRefFuncCode += $" catch (Exception e)\n";
  258. initRefFuncCode += $" {{\n";
  259. initRefFuncCode += $" GD.PrintErr(e.ToString());\n";
  260. initRefFuncCode += $" throw new Exception(\"初始化'{excelData.TableName}'引用其他表数据失败, 当前行id: \" + item.Id);\n";
  261. initRefFuncCode += $" }}\n";
  262. initRefFuncCode += $" }}\n";
  263. initRefFuncCode += $" }}\n";
  264. }
  265. }
  266.  
  267. code += fieldCode;
  268. code += $"\n";
  269. code += $" private static bool _init = false;\n";
  270. code += $" /// <summary>\n";
  271. code += $" /// 初始化所有配置表数据\n";
  272. code += $" /// </summary>\n";
  273. code += $" public static void Init()\n";
  274. code += $" {{\n";
  275. code += $" if (_init) return;\n";
  276. code += $" _init = true;\n";
  277. code += $"\n";
  278. code += callFuncCode;
  279. code += $"\n";
  280. code += callInitRefFuncCode;
  281. code += $" }}\n";
  282. code += funcCode;
  283. code += $"\n";
  284. code += initRefFuncCode;
  285. code += $" private static string _ReadConfigAsText(string path)\n";
  286. code += $" {{\n";
  287. code += $" var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);\n";
  288. code += $" var asText = file.GetAsText();\n";
  289. code += $" file.Dispose();\n";
  290. code += $" return asText;\n";
  291. code += $" }}\n";
  292. code += $"}}";
  293. return code;
  294. }
  295. private static ExcelData ReadExcel(string excelPath)
  296. {
  297. var excelData = new ExcelData();
  298. //文件名称
  299. var fileName = Path.GetFileNameWithoutExtension(excelPath).FirstToUpper();
  300. excelData.TableName = fileName;
  301. //输出代码
  302. var outStr = $"using System.Text.Json.Serialization;\n";
  303. outStr += $"using System.Collections.Generic;\n\n";
  304. outStr += $"namespace Config;\n\n";
  305. outStr += $"public static partial class ExcelConfig\n{{\n";
  306. outStr += $" public class {fileName}\n";
  307. outStr += $" {{\n";
  308. //继承的带有引用其他表的类代码
  309. var outRefStr = "";
  310. var cloneFuncStr = $" /// <summary>\n";
  311. cloneFuncStr += $" /// 返回浅拷贝出的新对象\n";
  312. cloneFuncStr += $" /// </summary>\n";
  313. cloneFuncStr += $" public {fileName} Clone()\n";
  314. cloneFuncStr += $" {{\n";
  315. cloneFuncStr += $" var inst = new {fileName}();\n";
  316. var sourceFile = excelPath;
  317. //列数
  318. var columnCount = -1;
  319. //加载表数据
  320. var workbook = new Workbook(sourceFile);
  321. using (workbook)
  322. {
  323. var sheet1 = workbook.Worksheets[0];
  324. var cells = sheet1.Cells;
  325. //先解析表中的列名, 注释, 类型
  326. var names = cells.Rows[0];
  327. var descriptions = cells.Rows[1];
  328. var types = cells.Rows[2];
  329.  
  330. columnCount = 0;
  331. foreach (Cell cell in names)
  332. {
  333. //字段名称
  334. var field = GetCellStringValue(cell);
  335. if (string.IsNullOrEmpty(field))
  336. {
  337. if (cell.Column == 0)
  338. {
  339. throw new Exception($"表'{fileName}'的列数为0!");
  340. }
  341. //到达最后一列了
  342. break;
  343. }
  344.  
  345. columnCount++;
  346. field = field.FirstToUpper();
  347. excelData.ColumnNames.Add(field);
  348. if (field == "Clone")
  349. {
  350. throw new Exception($"表'{fileName}'中不允许有'Clone'字段!");
  351. }
  352.  
  353. var descriptionCell = descriptions[cell.Column];
  354. //描述
  355. string description;
  356. if (descriptionCell != null)
  357. {
  358. description = GetCellStringValue(descriptionCell).Replace("\n", " <br/>\n /// ");
  359. }
  360. else
  361. {
  362. description = "";
  363. }
  364. //类型
  365. var typeString = GetCellStringValue(types[cell.Column]);
  366. if (string.IsNullOrEmpty(typeString))
  367. {
  368. throw new Exception($"表'{fileName}'中'{field}'这一列类型为空!");
  369. }
  370. //尝试解析类型
  371. MappingData mappingData;
  372. try
  373. {
  374. var autoParentheses = false;
  375. if (typeString.EndsWith('*'))
  376. {
  377. autoParentheses = true;
  378. typeString = typeString.TrimEnd('*');
  379. }
  380.  
  381. mappingData = ConvertToType(typeString.Replace(" ", ""));
  382. mappingData.AutoParentheses = autoParentheses;
  383. }
  384. catch (Exception e)
  385. {
  386. PrintError(e.ToString());
  387. throw new Exception($"表'{fileName}'中'{field}'这一列类型描述语法错误: {typeString}");
  388. }
  389. if (!excelData.ColumnMappingData.TryAdd(field, mappingData))
  390. {
  391. throw new Exception($"表'{fileName}'中存在相同名称的列: '{field}'!");
  392. }
  393. outStr += $" /// <summary>\n";
  394. outStr += $" /// {description}\n";
  395. outStr += $" /// </summary>\n";
  396. if (!mappingData.IsRefExcel) //没有引用其他表
  397. {
  398. outStr += $" [JsonInclude]\n";
  399. outStr += $" public {mappingData.TypeStr} {field};\n\n";
  400. }
  401. else
  402. {
  403. outStr += $" public {mappingData.RefTypeStr} {field};\n\n";
  404. }
  405.  
  406. if (mappingData.IsRefExcel) //引用其他表
  407. {
  408. if (string.IsNullOrEmpty(outRefStr))
  409. {
  410. outRefStr += $" private class Ref_{fileName} : {fileName}\n";
  411. outRefStr += $" {{\n";
  412. }
  413. outRefStr += $" [JsonInclude]\n";
  414. outRefStr += $" public {mappingData.TypeStr} __{field};\n\n";
  415. }
  416. cloneFuncStr += $" inst.{field} = {field};\n";
  417. }
  418. cloneFuncStr += " return inst;\n";
  419. cloneFuncStr += " }\n";
  420. outStr += cloneFuncStr;
  421. outStr += " }\n";
  422.  
  423. if (!string.IsNullOrEmpty(outRefStr))
  424. {
  425. outRefStr += " }\n";
  426. outStr += outRefStr;
  427. }
  428. outStr += "}";
  429. //解析字段类型
  430. foreach (var kv in excelData.ColumnMappingData)
  431. {
  432. var typeName = kv.Value.TypeName;
  433. var type = Type.GetType(typeName);
  434. if (type == null)
  435. {
  436. throw new Exception($"表'{fileName}'中'{kv.Key}'这一列类型未知! " + kv.Value.TypeStr);
  437. }
  438. excelData.ColumnType.Add(kv.Key, type);
  439. }
  440.  
  441. //解析数据
  442. foreach (Row row in cells.Rows)
  443. {
  444. if (row == null || row.Index < 3)
  445. {
  446. continue;
  447. }
  448. Dictionary<string, object> data = null;
  449. for (int j = 0; j < columnCount; j++)
  450. {
  451. var cell = row[j];
  452. var strValue = GetCellStringValue(cell);
  453. //如果这一行的第一列数据为空, 则跳过这一行
  454. if (j == 0 && string.IsNullOrEmpty(strValue))
  455. {
  456. break;
  457. }
  458. else if (data == null)
  459. {
  460. data = new Dictionary<string, object>();
  461. excelData.DataList.Add(data);
  462. }
  463.  
  464. var fieldName = excelData.ColumnNames[j];
  465. var mappingData = excelData.ColumnMappingData[fieldName];
  466. var field = mappingData.IsRefExcel ? "__" + fieldName : fieldName;
  467. try
  468. {
  469. switch (mappingData.TypeStr)
  470. {
  471. case "bool":
  472. case "boolean":
  473. data.Add(field, GetCellBooleanValue(cell));
  474. break;
  475. case "byte":
  476. data.Add(field, Convert.ToByte(GetCellNumberValue(cell)));
  477. break;
  478. case "sbyte":
  479. data.Add(field, Convert.ToSByte(GetCellNumberValue(cell)));
  480. break;
  481. case "short":
  482. data.Add(field, Convert.ToInt16(GetCellNumberValue(cell)));
  483. break;
  484. case "ushort":
  485. data.Add(field, Convert.ToUInt16(GetCellNumberValue(cell)));
  486. break;
  487. case "int":
  488. data.Add(field, Convert.ToInt32(GetCellNumberValue(cell)));
  489. break;
  490. case "uint":
  491. data.Add(field, Convert.ToUInt32(GetCellNumberValue(cell)));
  492. break;
  493. case "long":
  494. data.Add(field, Convert.ToInt64(GetCellNumberValue(cell)));
  495. break;
  496. case "ulong":
  497. data.Add(field, Convert.ToUInt64(GetCellNumberValue(cell)));
  498. break;
  499. case "float":
  500. data.Add(field, Convert.ToSingle(GetCellNumberValue(cell)));
  501. break;
  502. case "double":
  503. data.Add(field, GetCellNumberValue(cell));
  504. break;
  505. case "string":
  506. data.Add(field, GetCellStringValue(cell));
  507. break;
  508. default:
  509. {
  510. var cellStringValue = GetCellStringValue(cell);
  511. if (cellStringValue.Length == 0)
  512. {
  513. if (mappingData.TypeStr == nameof(ActivityQuality))
  514. {
  515. ActivityQuality v = default;
  516. data.Add(field, v);
  517. }
  518. else if (mappingData.TypeStr == nameof(ActivityType))
  519. {
  520. ActivityType v = default;
  521. data.Add(field, v);
  522. }
  523. else
  524. {
  525. data.Add(field, null);
  526. }
  527. }
  528. else
  529. {
  530. if (mappingData.AutoParentheses)
  531. {
  532. if (mappingData.CollectionsType == CollectionsType.Array)
  533. {
  534. cellStringValue = "[" + cellStringValue.TrimEnd(',') + "]";
  535. }
  536. if (mappingData.CollectionsType == CollectionsType.Map)
  537. {
  538. cellStringValue = "{" + cellStringValue.TrimEnd(',') + "}";
  539. }
  540. }
  541. data.Add(field, JsonSerializer.Deserialize(cellStringValue, excelData.ColumnType[fieldName]));
  542. }
  543. }
  544. break;
  545. }
  546. }
  547. catch (Exception e)
  548. {
  549. PrintError(e.ToString());
  550. throw new Exception($"解析表'{fileName}'第'{row.Index + 1}'行第'{j + 1}'列数据时发生异常");
  551. }
  552. }
  553. }
  554. }
  555.  
  556. excelData.OutCode = outStr;
  557. return excelData;
  558. }
  559.  
  560. private static string GetCellStringValue(Cell cell)
  561. {
  562. if (cell == null)
  563. {
  564. return "";
  565. }
  566. switch (cell.Type)
  567. {
  568. case CellValueType.IsNumeric:
  569. return cell.DoubleValue.ToString();
  570. case CellValueType.IsString:
  571. return cell.StringValue;
  572. case CellValueType.IsBool:
  573. return cell.BoolValue ? "true" : "false";
  574. }
  575.  
  576. return "";
  577. }
  578.  
  579. private static double GetCellNumberValue(Cell cell)
  580. {
  581. if (cell == null)
  582. {
  583. return 0;
  584. }
  585. switch (cell.Type)
  586. {
  587. case CellValueType.IsNumeric:
  588. return cell.DoubleValue;
  589. case CellValueType.IsString:
  590. return double.Parse(cell.StringValue);
  591. case CellValueType.IsBool:
  592. return cell.BoolValue ? 1 : 0;
  593. }
  594. return 0;
  595. }
  596.  
  597. private static bool GetCellBooleanValue(Cell cell)
  598. {
  599. if (cell == null)
  600. {
  601. return false;
  602. }
  603. switch (cell.Type)
  604. {
  605. case CellValueType.IsNumeric:
  606. return cell.DoubleValue != 0;
  607. case CellValueType.IsString:
  608. {
  609. var value = cell.StringValue;
  610. if (string.IsNullOrWhiteSpace(value))
  611. {
  612. return false;
  613. }
  614. return bool.Parse(value);
  615. }
  616. case CellValueType.IsBool:
  617. return cell.BoolValue;
  618. }
  619.  
  620. return false;
  621. }
  622.  
  623. private static MappingData ConvertToType(string str, int depth = 0)
  624. {
  625. if (Regex.IsMatch(str, "^\\w+$"))
  626. {
  627. var typeStr = TypeStrMapping(str);
  628. var typeName = TypeNameMapping(str);
  629. return new MappingData(typeStr, typeName, CollectionsType.None);
  630. }
  631. else if (Regex.IsMatch(str, "^\\$\\w+$")) //引用其他表
  632. {
  633. var realName = str.Substring(1);
  634. if (!_excelNames.Contains(realName))
  635. {
  636. throw new Exception($"引用表数据失败, 未找到表: {realName}!");
  637. }
  638.  
  639. if (depth > 1)
  640. {
  641. throw new Exception("引用表数据失败, 引用表数据仅支持放入第一层的数组和字典!");
  642. }
  643.  
  644. return new MappingData(TypeStrMapping("string"), TypeNameMapping("string"), CollectionsType.None, realName, realName);
  645. }
  646. else if (str.StartsWith('{')) //字典
  647. {
  648. var tempStr = str.Substring(1, str.Length - 2);
  649. var index = tempStr.IndexOf(':');
  650. if (index == -1)
  651. {
  652. throw new Exception("类型描述语法错误!");
  653. }
  654.  
  655. var keyStr = tempStr.Substring(0, index);
  656. if (!IsBaseType(keyStr))
  657. {
  658. throw new Exception($"字典key类型必须是基础类型!");
  659. }
  660.  
  661. var type1 = ConvertToType(keyStr, depth + 1);
  662. var type2 = ConvertToType(tempStr.Substring(index + 1), depth + 1);
  663.  
  664. var typeStr = $"Dictionary<{type1.TypeStr}, {type2.TypeStr}>";
  665. var typeName = $"System.Collections.Generic.Dictionary`2[[{type1.TypeName}],[{type2.TypeName}]]";
  666.  
  667. if (type2.IsRefExcel) //引用过其他表
  668. {
  669. var refTypeStr = $"Dictionary<{type1.TypeStr}, {type2.RefTypeStr}>";
  670. return new MappingData(typeStr, typeName, CollectionsType.Map, refTypeStr, type2.RefTypeName);
  671. }
  672.  
  673. return new MappingData(typeStr, typeName, CollectionsType.Map);
  674. }
  675. else if (str.StartsWith('[')) //数组
  676. {
  677. var tempStr = str.Substring(1, str.Length - 2);
  678. var typeData = ConvertToType(tempStr, depth + 1);
  679. var typeStr = typeData.TypeStr + "[]";
  680. var typeName = typeData.TypeName + "[]";
  681.  
  682. if (typeData.IsRefExcel) //引用过其他表
  683. {
  684. var refTypeStr = typeData.RefTypeStr + "[]";
  685. return new MappingData(typeStr, typeName, CollectionsType.Array, refTypeStr, typeData.RefTypeName);
  686. }
  687. return new MappingData(typeStr, typeName, CollectionsType.Array);
  688. }
  689. throw new Exception("类型描述语法错误!");
  690. }
  691. private static string TypeStrMapping(string typeName)
  692. {
  693. switch (typeName)
  694. {
  695. case "boolean": return "bool";
  696. case "vector2": return "SerializeVector2";
  697. case "vector3": return "SerializeVector3";
  698. case "color": return "SerializeColor";
  699. case "activityType": return "ActivityType";
  700. case "activityQuality": return "ActivityQuality";
  701. }
  702.  
  703. return typeName;
  704. }
  705.  
  706. private static string TypeNameMapping(string typeName)
  707. {
  708. switch (typeName)
  709. {
  710. case "bool":
  711. case "boolean": return typeof(bool).FullName;
  712. case "byte": return typeof(byte).FullName;
  713. case "sbyte": return typeof(sbyte).FullName;
  714. case "short": return typeof(short).FullName;
  715. case "ushort": return typeof(ushort).FullName;
  716. case "int": return typeof(int).FullName;
  717. case "uint": return typeof(uint).FullName;
  718. case "long": return typeof(long).FullName;
  719. case "ulong": return typeof(ulong).FullName;
  720. case "string": return typeof(string).FullName;
  721. case "float": return typeof(float).FullName;
  722. case "double": return typeof(double).FullName;
  723. case "vector2": return "SerializeVector2";
  724. case "vector3": return "SerializeVector3";
  725. case "color": return "SerializeColor";
  726. case "activityType": return "ActivityType";
  727. case "activityQuality": return "ActivityQuality";
  728. }
  729.  
  730. return typeName;
  731. }
  732.  
  733. private static bool IsBaseType(string typeName)
  734. {
  735. switch (typeName)
  736. {
  737. case "bool":
  738. case "boolean":
  739. case "byte":
  740. case "sbyte":
  741. case "short":
  742. case "ushort":
  743. case "int":
  744. case "uint":
  745. case "long":
  746. case "ulong":
  747. case "string":
  748. case "float":
  749. case "double":
  750. return true;
  751. }
  752.  
  753. return false;
  754. }
  755. private static void PrintError(string message)
  756. {
  757. Console.ForegroundColor = ConsoleColor.Red;
  758. Console.WriteLine(message);
  759. Console.ResetColor();
  760. }
  761. /// <summary>
  762. /// 字符串首字母小写
  763. /// </summary>
  764. public static string FirstToLower(this string str)
  765. {
  766. return str.Substring(0, 1).ToLower() + str.Substring(1);
  767. }
  768. /// <summary>
  769. /// 字符串首字母大写
  770. /// </summary>
  771. public static string FirstToUpper(this string str)
  772. {
  773. return str.Substring(0, 1).ToUpper() + str.Substring(1);
  774. }
  775. }