117 lines
5.0 KiB
C#
117 lines
5.0 KiB
C#
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,
|
|
};
|
|
}
|
|
}
|