using AscNet.Logging; using System.Reflection; namespace AscNet.Common.Util { #pragma warning disable CS8618, CS8602 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. public abstract class TableReader { public List All { get; set; } protected abstract string FilePath { get; } private readonly Logger c = new(typeof(TableReader), nameof(TableReader), LogLevel.DEBUG, LogLevel.DEBUG); private static TSelf _instance; public static TSelf Instance { get { _instance ??= Activator.CreateInstance(); // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if ((_instance as TableReader).All == null) { (_instance as TableReader).Load(); (_instance as TableReader).c.Debug($"{typeof(TSelf).Name} Excel Loaded From {(_instance as TableReader).FilePath}"); } return _instance; } } public abstract void Load(); } public interface ITable { abstract static string File { get; } } public static class TableReaderV2 { private static readonly Dictionary cache = new(); private static readonly Logger c = new(typeof(TableReaderV2), nameof(TableReaderV2), LogLevel.DEBUG, LogLevel.DEBUG); public static List Parse() where T : ITable { if (cache.ContainsKey(typeof(T))) { return (List)cache.GetValueOrDefault(typeof(T))!; } List result = new(); try { using (var reader = new StreamReader(T.File)) { // Read the header line to get column names string headerLine = reader.ReadLine()!; string[] columnNames = headerLine.Split('\t'); // Read data lines and parse them into objects while (!reader.EndOfStream) { string dataLine = reader.ReadLine()!; if (string.IsNullOrEmpty(dataLine)) break; string[] values = dataLine.Split('\t'); T obj = MapToObject(columnNames, values); result.Add(obj); } } c.Debug($"{typeof(T).Name} Loaded From {T.File}"); cache.Add(typeof(T), result); } catch (Exception ex) { c.Error($"An error occurred: {ex.Message}"); } return result; } static T MapToObject(string[] columnNames, string[] values) where T : ITable { T obj = Activator.CreateInstance(); for (int i = 0; i < Math.Min(columnNames.Length, values.Length); i++) { PropertyInfo? prop = typeof(T).GetProperty(columnNames[i].Split('[').First()); if (prop != null) { if (prop.PropertyType == typeof(List)) { if (prop.GetValue(obj) is null) { prop.SetValue(obj, new List()); } string value = values[i]; if (!string.IsNullOrEmpty(value)) { prop.PropertyType.GetMethod("Add").Invoke(prop.GetValue(obj), new object[] { int.Parse(value) }); } } else if (prop.PropertyType == typeof(List)) { if (prop.GetValue(obj) is null) { prop.SetValue(obj, new List()); } string value = values[i]; if (!string.IsNullOrEmpty(value)) { prop.PropertyType.GetMethod("Add").Invoke(prop.GetValue(obj), new object[] { value }); } } else if (prop.PropertyType == typeof(int) || prop.PropertyType == typeof(int?)) { if (!string.IsNullOrEmpty(values[i])) prop.SetValue(obj, int.Parse(values[i])); else prop.SetValue(obj, null); } else { prop.SetValue(obj, values[i]); } } } return obj; } } }