ascnet/AscNet.Common/Util/TableReader.cs

137 lines
4.9 KiB
C#
Raw Permalink Normal View History

2023-10-18 08:49:36 +00:00
using AscNet.Logging;
using System.Reflection;
2023-10-18 08:49:36 +00:00
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<TSelf, TScheme>
{
public List<TScheme> All { get; set; }
protected abstract string FilePath { get; }
2023-10-18 14:45:13 +00:00
private readonly Logger c = new(typeof(TableReader<TSelf, TScheme>), nameof(TableReader<TSelf, TScheme>), LogLevel.DEBUG, LogLevel.DEBUG);
2023-10-18 08:49:36 +00:00
private static TSelf _instance;
public static TSelf Instance
{
get
{
_instance ??= Activator.CreateInstance<TSelf>();
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if ((_instance as TableReader<TSelf, TScheme>).All == null)
{
(_instance as TableReader<TSelf, TScheme>).Load();
(_instance as TableReader<TSelf, TScheme>).c.Debug($"{typeof(TSelf).Name} Excel Loaded From {(_instance as TableReader<TSelf, TScheme>).FilePath}");
}
return _instance;
}
}
2023-10-18 14:45:13 +00:00
public abstract void Load();
2023-10-18 08:49:36 +00:00
}
public interface ITable
{
abstract static string File { get; }
}
public static class TableReaderV2
{
2023-11-25 12:43:22 +00:00
private static readonly Dictionary<Type, object> cache = new();
private static readonly Logger c = new(typeof(TableReaderV2), nameof(TableReaderV2), LogLevel.DEBUG, LogLevel.DEBUG);
public static List<T> Parse<T>() where T : ITable
{
2023-11-25 12:43:22 +00:00
if (cache.ContainsKey(typeof(T)))
{
return (List<T>)cache.GetValueOrDefault(typeof(T))!;
}
List<T> 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<T>(columnNames, values);
result.Add(obj);
}
}
2023-11-25 12:43:22 +00:00
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<T>(string[] columnNames, string[] values) where T : ITable
{
T obj = Activator.CreateInstance<T>();
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<int>))
{
if (prop.GetValue(obj) is null)
{
prop.SetValue(obj, new List<int>());
}
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<string>))
{
if (prop.GetValue(obj) is null)
{
prop.SetValue(obj, new List<string>());
}
string value = values[i];
if (!string.IsNullOrEmpty(value))
{
prop.PropertyType.GetMethod("Add").Invoke(prop.GetValue(obj), new object[] { value });
}
}
2023-11-24 13:01:26 +00:00
else if (prop.PropertyType == typeof(int) || prop.PropertyType == typeof(int?))
{
2023-11-24 13:01:26 +00:00
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;
}
}
2023-10-18 08:49:36 +00:00
}