Продолжаем работать с билдером

This commit is contained in:
2025-10-07 18:28:45 +04:00
parent 95345c940f
commit 99952c66e3
15 changed files with 1055 additions and 517 deletions
@@ -0,0 +1,116 @@
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Pf2e.Web.Helpers.Format;
namespace Pf2e.Web.Helpers.Serialization;
/// <summary>
/// Построитель группы полей для типа TField.
/// </summary>
/// <typeparam name="TField">Тип сущности для группы полей.</typeparam>
public class FieldGroupBuilder<TField>(string name)
where TField : class
{
private readonly FieldGroupDefinition _groupDefinition = new()
{
Name = name,
GroupType = typeof(TField),
};
/// <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;
// Получаем атрибут CommentAttribute, если он есть
CommentAttribute? commentAttribute = propertyInfo.GetCustomAttribute<CommentAttribute>();
string fieldName = commentAttribute?.Comment ?? propertyInfo.Name;
Type fieldType = propertyInfo.PropertyType;
_groupDefinition.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)
{
_groupDefinition.Fields.Last().ValueFormatter = valueFormatter;
return this;
}
/// <summary>
/// Использует комментарий из другого поля для установки имени последнего добавленного поля.
/// </summary>
/// <param name="fieldExpression">Лямбда-выражение для получения поля с комментарием.</param>
/// <returns>Текущий экземпляр построителя группы полей.</returns>
public FieldGroupBuilder<TField> UseCommentFrom(
Expression<Func<TField, object>> fieldExpression
)
{
// Получаем информацию о свойстве из выражения
MemberExpression? memberExpression = GetMemberExpression(fieldExpression.Body);
if (memberExpression == null)
{
throw new ArgumentException(
"Выражение должно быть доступом к свойству",
nameof(fieldExpression)
);
}
PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member;
// Получаем атрибут CommentAttribute, если он есть
CommentAttribute? commentAttribute = propertyInfo.GetCustomAttribute<CommentAttribute>();
if (commentAttribute != null)
{
// Устанавливаем имя последнего добавленного поля
if (_groupDefinition.Fields.Count > 0)
{
_groupDefinition.Fields.Last().Name = commentAttribute.Comment;
}
}
return this;
}
/// <summary>
/// Завершает построение группы полей и возвращает определение группы.
/// </summary>
/// <returns>Итоговое определение группы полей.</returns>
public FieldGroupDefinition Build() => _groupDefinition;
/// <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,
};
}
}