Продолжаем работать с билдером
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
using System.Reflection;
|
||||
using Pf2e.Web.Helpers.Format;
|
||||
|
||||
namespace Pf2e.Web.Helpers.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Построитель сериализации для сущности.
|
||||
/// </summary>
|
||||
/// <param name="type">Тип сущности для сериализации.</param>
|
||||
public abstract class EntityBuilder(Type type)
|
||||
{
|
||||
/// <summary>
|
||||
/// Тип сущности для сериализации.
|
||||
/// </summary>
|
||||
public Type EntityType { get; } = type;
|
||||
|
||||
/// <summary>
|
||||
/// Сериализует объект в список групп полей.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public abstract List<SerializationGroup> Compile(object value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Построитель сериализации для типа T.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">Тип сущности для сериализации.</typeparam>
|
||||
public class EntityBuilder<TEntity>() : EntityBuilder(typeof(TEntity))
|
||||
where TEntity : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Список групп полей.
|
||||
/// </summary>
|
||||
public List<FieldGroupDefinition> Groups { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет группу полей в построитель сериализации.
|
||||
/// </summary>
|
||||
/// <param name="name">Название группы.</param>
|
||||
/// <param name="configure">Делегат для настройки группы полей.</param>
|
||||
/// <returns>Текущий экземпляр построителя.</returns>
|
||||
public EntityBuilder<TEntity> AddGroup(
|
||||
string name,
|
||||
Action<FieldGroupBuilder<TEntity>> configure
|
||||
)
|
||||
{
|
||||
FieldGroupBuilder<TEntity> groupBuilder = new(name);
|
||||
configure(groupBuilder);
|
||||
Groups.Add(groupBuilder.Build());
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет группу полей в построитель сериализации с названием типа.
|
||||
/// </summary>
|
||||
/// <param name="configure">Делегат для настройки группы полей.</param>
|
||||
/// <returns>Текущий экземпляр построителя.</returns>
|
||||
public EntityBuilder<TEntity> AddGroup(Action<FieldGroupBuilder<TEntity>> configure)
|
||||
{
|
||||
return AddGroup(typeof(TEntity).Name, configure);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override List<SerializationGroup> Compile(object value)
|
||||
{
|
||||
return Groups.Select(group => CompileGroup(group, value)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Строит группу полей.
|
||||
/// </summary>
|
||||
/// <returns>Готовая группа полей.</returns>
|
||||
public SerializationGroup CompileGroup(FieldGroupDefinition groupDefinition, object value)
|
||||
{
|
||||
SerializationGroup result = new() { Name = groupDefinition.Name };
|
||||
|
||||
foreach (FieldDefinition field in groupDefinition.Fields)
|
||||
{
|
||||
PropertyInfo? propertyInfo = groupDefinition.GroupType.GetProperty(field.Name);
|
||||
|
||||
if (propertyInfo == null)
|
||||
continue;
|
||||
|
||||
object? fieldValue = propertyInfo.GetValue(value);
|
||||
|
||||
result.Fields.Add(CompileField(field, fieldValue));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Построение поля сериализации.
|
||||
/// </summary>
|
||||
/// <param name="field">Определение поля.</param>
|
||||
/// <param name="value">Значение поля.</param>
|
||||
/// <returns>Построенное поле сериализации.</returns>
|
||||
private SerializationField CompileField(FieldDefinition field, object? value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = field.Name,
|
||||
Type = field.Type.Name,
|
||||
Value = "null",
|
||||
IsImplemented = true,
|
||||
};
|
||||
}
|
||||
|
||||
if (field.ValueFormatter is not null)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = field.Name,
|
||||
Type = field.Type.Name,
|
||||
Value = field.ValueFormatter(value),
|
||||
IsImplemented = true,
|
||||
};
|
||||
}
|
||||
|
||||
ValueFormatter? formatter = Formatters.SelectFormatter(value);
|
||||
|
||||
if (formatter is not null)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = field.Name,
|
||||
Type = field.Type.Name,
|
||||
Value = formatter.Format(value),
|
||||
IsImplemented = true,
|
||||
};
|
||||
}
|
||||
|
||||
return new()
|
||||
{
|
||||
Name = field.Name,
|
||||
Type = field.Type.Name,
|
||||
Value = value.ToString() ?? "null",
|
||||
IsImplemented = false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Pf2e.Web.Helpers.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Информация о поле.
|
||||
/// </summary>
|
||||
public class FieldDefinition
|
||||
{
|
||||
/// <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;
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Pf2e.Web.Helpers.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Группа полей.
|
||||
/// </summary>
|
||||
public class FieldGroupDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Название группы.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Тип класса, к которому относится поля группы.
|
||||
/// </summary>
|
||||
public Type GroupType { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Список полей в группе.
|
||||
/// </summary>
|
||||
public List<FieldDefinition> Fields { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace Pf2e.Web.Helpers.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Результат сериализации сущности.
|
||||
/// </summary>
|
||||
public class SerializationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Группы полей.
|
||||
/// </summary>
|
||||
public List<SerializationGroup> Groups { get; set; } = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Группа полей для сериализации.
|
||||
/// </summary>
|
||||
public class SerializationGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// Название группы.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Список полей в группе.
|
||||
/// </summary>
|
||||
public List<SerializationField> Fields { get; set; } = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Поле для сериализации.
|
||||
/// </summary>
|
||||
public class SerializationField
|
||||
{
|
||||
/// <summary>
|
||||
/// Название поля.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Значение поля в строковом представлении.
|
||||
/// </summary>
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Значение поля в строковом представлении.
|
||||
/// </summary>
|
||||
public string Value { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Флаг, указывающий, реализовано ли поле (true) или нет (false).
|
||||
/// </summary>
|
||||
public bool IsImplemented { get; set; } = true;
|
||||
}
|
||||
Reference in New Issue
Block a user