forked from PGR/ascnet
137 lines
4.9 KiB
C#
137 lines
4.9 KiB
C#
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<TSelf, TScheme>
|
|
{
|
|
public List<TScheme> All { get; set; }
|
|
protected abstract string FilePath { get; }
|
|
private readonly Logger c = new(typeof(TableReader<TSelf, TScheme>), nameof(TableReader<TSelf, TScheme>), LogLevel.DEBUG, LogLevel.DEBUG);
|
|
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;
|
|
}
|
|
}
|
|
|
|
public abstract void Load();
|
|
}
|
|
|
|
public interface ITable
|
|
{
|
|
abstract static string File { get; }
|
|
}
|
|
|
|
public static class TableReaderV2
|
|
{
|
|
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
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
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 });
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|