Files
Pf2eDataScrapper/Pf2e/Web/Helpers/SerializationBuilder.cs
T

152 lines
5.8 KiB
C#

using System.Linq.Expressions;
using System.Reflection;
namespace Pf2e.Web.Helpers;
/// <summary>
/// Построитель сериализации для типа T.
/// </summary>
/// <typeparam name="T">Тип сущности для сериализации.</typeparam>
public class SerializationBuilder<T>
where T : class
{
/// <summary>
/// Список групп полей.
/// </summary>
public List<FieldGroup> Groups { get; set; } = [];
/// <summary>
/// Форматтер полей сущности.
/// </summary>
protected EntityFieldFormatter FieldFormatter { get; } = new();
/// <summary>
/// Добавляет группу полей в построитель сериализации.
/// </summary>
/// <param name="name">Название группы.</param>
/// <param name="configure">Делегат для настройки группы полей.</param>
/// <returns>Текущий экземпляр построителя.</returns>
public SerializationBuilder<T> AddGroup(string name, Action<FieldGroupBuilder<T>> configure)
{
FieldGroupBuilder<T> groupBuilder = new(name);
configure(groupBuilder);
Groups.Add(groupBuilder.Build());
return this;
}
/// <summary>
/// Добавляет группу полей в построитель сериализации с названием типа.
/// </summary>
/// <param name="configure">Делегат для настройки группы полей.</param>
/// <returns>Текущий экземпляр построителя.</returns>
public SerializationBuilder<T> AddGroup(Action<FieldGroupBuilder<T>> configure)
{
return AddGroup(typeof(T).Name, configure);
}
/// <summary>
/// Построитель группы полей для типа TField.
/// </summary>
/// <typeparam name="TField">Тип сущности для группы полей.</typeparam>
public class FieldGroupBuilder<TField>(string name)
where TField : class
{
private readonly FieldGroup _group = new() { Name = name };
/// <summary>
/// Добавляет поле в группу.
/// </summary>
/// <param name="fieldExpression">Лямбда-выражение для получения поля.</param>
/// <returns>Текущий экземпляр построителя группы полей.</returns>
public FieldGroupBuilder<TField> AddField(Expression<Func<TField, object>> fieldExpression)
{
// Получаем информацию о свойстве из выражения
MemberExpression? memberExpression = GetMemberExpression(fieldExpression.Body);
if (memberExpression == null)
{
throw new ArgumentException(
"Выражение должно быть доступом к свойству",
nameof(fieldExpression)
);
}
PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member;
string fieldName = propertyInfo.Name;
Type fieldType = propertyInfo.PropertyType;
_group.Fields.Add(new() { Name = fieldName, Type = fieldType });
return this;
}
/// <summary>
/// Устанавливает форматтер значения для последнего добавленного поля.
/// </summary>
/// <param name="valueFormatter">Функция форматирования значения.</param>
/// <returns>Текущий экземпляр построителя группы полей.</returns>
public FieldGroupBuilder<TField> SetValueFormatter(Func<object, string> valueFormatter)
{
_group.Fields.Last().ValueFormatter = valueFormatter;
return this;
}
/// <summary>
/// Строит группу полей.
/// </summary>
/// <returns>Готовая группа полей.</returns>
public FieldGroup Build() => _group;
/// <summary>
/// Получает MemberExpression из тела лямбда-выражения.
/// </summary>
/// <param name="expression">Тело выражения.</param>
/// <returns>MemberExpression или null, если не удалось получить.</returns>
private static MemberExpression? GetMemberExpression(Expression expression)
{
return expression switch
{
MemberExpression memberExpression => memberExpression,
UnaryExpression { NodeType: ExpressionType.Convert } unaryExpression =>
unaryExpression.Operand as MemberExpression,
_ => null,
};
}
}
/// <summary>
/// Группа полей.
/// </summary>
public class FieldGroup
{
/// <summary>
/// Название группы.
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// Список полей в группе.
/// </summary>
public List<FieldBuilderDefinition> Fields { get; set; } = [];
}
/// <summary>
/// Информация о поле.
/// </summary>
public class FieldBuilderDefinition
{
/// <summary>
/// Название поля.
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// Тип поля.
/// </summary>
public required Type Type { get; set; }
/// <summary>
/// Форматтер значения поля.
/// </summary>
public Func<object, string>? ValueFormatter { get; set; } = null;
}
}