diff --git a/Pf2e/Web/Helpers/EntitySerializer.cs b/Pf2e/Web/Helpers/EntitySerializer.cs index 02bab2f..1ce0f39 100644 --- a/Pf2e/Web/Helpers/EntitySerializer.cs +++ b/Pf2e/Web/Helpers/EntitySerializer.cs @@ -16,15 +16,6 @@ public class EntitySerializer public List Groups { get; set; } = []; } - /// - /// Группа полей. - /// - public class FieldGroup - { - public string Name { get; set; } = string.Empty; - public List Fields { get; set; } = []; - } - /// /// Информация о поле. /// @@ -49,21 +40,21 @@ public class EntitySerializer { SerializationResult result = new(); - // Группа для основных полей Entity - FieldGroup entityGroup = new() { Name = "Основные поля" }; - AddFieldsToGroup(entityGroup, fullEntity.Entity); - result.Groups.Add(entityGroup); + //// Группа для основных полей Entity + //FieldGroup entityGroup = new() { Name = "Основные поля" }; + //AddFieldsToGroup(entityGroup, fullEntity.Entity); + //result.Groups.Add(entityGroup); - // Группа для полей IEntity (SubEntity) - if (fullEntity.SubEntity != null) - { - FieldGroup subEntityGroup = new() - { - Name = "Поля " + fullEntity.SubEntity.GetType().Name, - }; - AddFieldsToGroup(subEntityGroup, fullEntity.SubEntity); - result.Groups.Add(subEntityGroup); - } + //// Группа для полей IEntity (SubEntity) + //if (fullEntity.SubEntity != null) + //{ + // FieldGroup subEntityGroup = new() + // { + // Name = "Поля " + fullEntity.SubEntity.GetType().Name, + // }; + // AddFieldsToGroup(subEntityGroup, fullEntity.SubEntity); + // result.Groups.Add(subEntityGroup); + //} return result; } @@ -71,25 +62,25 @@ public class EntitySerializer /// /// Добавить поля объекта в группу. /// - private void AddFieldsToGroup(FieldGroup group, object obj) - { - Type type = obj.GetType(); - PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); + //private void AddFieldsToGroup(FieldGroup group, object obj) + //{ + // Type type = obj.GetType(); + // PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); - foreach (PropertyInfo property in properties) - { - // Пропускаем навигационные свойства Entity - if (property.Name == "Entity") - continue; + // foreach (PropertyInfo property in properties) + // { + // // Пропускаем навигационные свойства Entity + // if (property.Name == "Entity") + // continue; - object? value = property.GetValue(obj); - FieldInfo fieldInfo = CreateFieldInfo(property, value); - group.Fields.Add(fieldInfo); - } - } + // object? value = property.GetValue(obj); + // FieldBuilderDefinition fieldInfo = CreateFieldInfo(property, value); + // group.Fields.Add(fieldInfo); + // } + //} /// - /// Создать FieldInfo для свойства. + /// Создать FieldBuilderDefinition для свойства. /// /// Поле класса. /// Значение поля. diff --git a/Pf2e/Web/Helpers/SerializationBuilder.cs b/Pf2e/Web/Helpers/SerializationBuilder.cs new file mode 100644 index 0000000..9137b70 --- /dev/null +++ b/Pf2e/Web/Helpers/SerializationBuilder.cs @@ -0,0 +1,151 @@ +using System.Linq.Expressions; +using System.Reflection; + +namespace Pf2e.Web.Helpers; + +/// +/// Построитель сериализации для типа T. +/// +/// Тип сущности для сериализации. +public class SerializationBuilder + where T : class +{ + /// + /// Список групп полей. + /// + public List Groups { get; set; } = []; + + /// + /// Форматтер полей сущности. + /// + protected EntityFieldFormatter FieldFormatter { get; } = new(); + + /// + /// Добавляет группу полей в построитель сериализации. + /// + /// Название группы. + /// Делегат для настройки группы полей. + /// Текущий экземпляр построителя. + public SerializationBuilder AddGroup(string name, Action> configure) + { + FieldGroupBuilder groupBuilder = new(name); + configure(groupBuilder); + Groups.Add(groupBuilder.Build()); + return this; + } + + /// + /// Добавляет группу полей в построитель сериализации с названием типа. + /// + /// Делегат для настройки группы полей. + /// Текущий экземпляр построителя. + public SerializationBuilder AddGroup(Action> configure) + { + return AddGroup(typeof(T).Name, configure); + } + + /// + /// Построитель группы полей для типа TField. + /// + /// Тип сущности для группы полей. + public class FieldGroupBuilder(string name) + where TField : class + { + private readonly FieldGroup _group = new() { Name = name }; + + /// + /// Добавляет поле в группу. + /// + /// Лямбда-выражение для получения поля. + /// Текущий экземпляр построителя группы полей. + public FieldGroupBuilder AddField(Expression> 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; + } + + /// + /// Устанавливает форматтер значения для последнего добавленного поля. + /// + /// Функция форматирования значения. + /// Текущий экземпляр построителя группы полей. + public FieldGroupBuilder SetValueFormatter(Func valueFormatter) + { + _group.Fields.Last().ValueFormatter = valueFormatter; + return this; + } + + /// + /// Строит группу полей. + /// + /// Готовая группа полей. + public FieldGroup Build() => _group; + + /// + /// Получает MemberExpression из тела лямбда-выражения. + /// + /// Тело выражения. + /// MemberExpression или null, если не удалось получить. + private static MemberExpression? GetMemberExpression(Expression expression) + { + return expression switch + { + MemberExpression memberExpression => memberExpression, + UnaryExpression { NodeType: ExpressionType.Convert } unaryExpression => + unaryExpression.Operand as MemberExpression, + _ => null, + }; + } + } + + /// + /// Группа полей. + /// + public class FieldGroup + { + /// + /// Название группы. + /// + public string Name { get; set; } = string.Empty; + + /// + /// Список полей в группе. + /// + public List Fields { get; set; } = []; + } + + /// + /// Информация о поле. + /// + public class FieldBuilderDefinition + { + /// + /// Название поля. + /// + public string Name { get; set; } = string.Empty; + + /// + /// Тип поля. + /// + public required Type Type { get; set; } + + /// + /// Форматтер значения поля. + /// + public Func? ValueFormatter { get; set; } = null; + } +}