This commit is contained in:
2025-05-05 14:45:58 +03:00
parent 0fb4058186
commit 90dd893f3e
43 changed files with 2501 additions and 63 deletions

View File

@@ -4,36 +4,44 @@
/// Обработчик параметров консоли
/// </summary>
/// <param name="consoleParams">Параметры консоли</param>
public sealed class ConsoleParamsParser (IEnumerable<string> consoleParams)
/// <param name="caseSensitive">Регистрозависимые ли параметры</param>
public sealed class ConsoleParamsParser(IEnumerable<string> consoleParams, bool caseSensitive = true)
{
/// <summary>
/// Массив параметров
/// </summary>
private readonly KeyValueList<string, string?> _paramsList = ParseConsoleParams(consoleParams);
private readonly KeyValueList<string, string?> _paramsList = ParseConsoleParams(consoleParams, caseSensitive);
/// <summary>
/// Парсер параметров
/// </summary>
/// <param name="paramsList">Входящий список параметров</param>
/// <returns></returns>
private static KeyValueList<string, string?> ParseConsoleParams (IEnumerable<string> paramsList)
/// <param name="caseSensitive">Регистрозависимые ли параметры</param>
/// <returns>Список параметров</returns>
private static KeyValueList<string, string?> ParseConsoleParams(IEnumerable<string> paramsList,
bool caseSensitive = true)
{
//Создаю список параметров
// Создаю список параметров
KeyValueList<string, string?> result = [];
//Заполняю его
// Заполняю его
foreach (string consoleParam in paramsList)
{
//Индекс знака "="
// Индекс знака "="
int eqPlace = consoleParam.IndexOf('=');
//Получаю параметр
// Получаю параметр
string param = eqPlace > -1 ? consoleParam[..eqPlace] : consoleParam;
//Получаю значение параметра
string? value = eqPlace == -1 ? null : consoleParam[(eqPlace + 1)..].Trim(new[] { '"' });
// Проверяю, требуются ли регистрозависимые параметры
if (!caseSensitive)
// - если нет, то переводим в нижний регистр
param = param.ToLower();
//Сохраняю в списке
// Получаю значение параметра
string? value = eqPlace == -1 ? null : consoleParam[(eqPlace + 1)..].Trim(['"']);
// Сохраняю в списке
result.Add(param.ToLower(), value);
}
@@ -46,21 +54,76 @@ public sealed class ConsoleParamsParser (IEnumerable<string> consoleParams)
/// </summary>
/// <param name="param">Параметр</param>
/// <returns>Есть ли параметр в списке</returns>
public bool HasParam (string param) =>
_paramsList.Any(keyValue => keyValue.Key == param.ToLower());
// ReSharper disable once MemberCanBePrivate.Global
public bool HasParam(string param)
{
// Проверяю регистрозависимость
if (!caseSensitive)
// - если нет, то переводим в нижний регистр
param = param.ToLower();
// Проверяю наличие параметра
return _paramsList.Any(keyValue => keyValue.Key == param.ToLower());
}
/// <summary>
/// Получает значение параметра
/// Проверяет наличие параметров
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public string? GetValue (string param) =>
!HasParam(param) ? null : _paramsList.FirstOrDefault(keyValue => keyValue.Key == param.ToLower()).Value;
/// <param name="params">Массив параметров</param>
/// <returns>Задан ли хотя бы один параметр</returns>
public bool HasParams(IEnumerable<string> @params) =>
@params.Aggregate(false, (current, param) => current || HasParam(param));
/// <summary>
/// Получает значение параметра,
/// </summary>
/// <param name="param">Имя параметра</param>
/// <param name="default">Значение по умолчанию</param>
/// <returns>Значение параметра или значение по умолчанию</returns>
public string GetValue(string param, string @default = "") =>
!HasParam(param)
? @default
: _paramsList.FirstOrDefault(keyValue => keyValue.Key == param.ToLower()).Value ?? @default;
/// <summary>
/// Получает значения параметров из списка.
/// </summary>
/// <param name="params">Список параметров</param>
/// <returns>Список значений параметров</returns>
public IEnumerable<string> GetValue(IEnumerable<string> @params)
{
// Задаю результат
List<string> result = [];
// Получаю список параметров
List<string> paramsList = @params.ToList();
// Проверяю наличие параметров
if (!HasParams(paramsList))
// - если нет, возвращаю значение по умолчанию
return [];
// Для каждого параметра, если задано значение - добавляю его в результат
result.AddRange(paramsList.Where(HasParam).Select(param => GetValue(param))
.Where(value => !string.IsNullOrWhiteSpace(value)));
// Возвращаю результат
return result;
}
/// <summary>
/// Получает значение первого заданного параметра и возвращает значение по умолчанию, если ни один из параметров не задан.
/// </summary>
/// <param name="params">Список параметров</param>
/// <param name="default">Значение по умолчанию</param>
/// <returns>Значение первого заданного параметра из списка или значение по умолчанию</returns>
public string GetValue(IEnumerable<string> @params, string @default) =>
GetValue(@params).FirstOrDefault() ?? @default;
/// <summary>
/// Получает список всех параметров
/// </summary>
/// <returns>Список всех параметров</returns>
public List<string> GetParamsList () =>
public List<string> GetParamsList() =>
_paramsList.Select(static keyValue => keyValue.Key.ToLower()).ToList();
}

View File

@@ -26,7 +26,6 @@ public class KeyValueList<TK, TV>: IEnumerable<KeyValue<TK, TV>>, ISerializable
#endregion
#region Методы
/// <summary>
/// Получает список ключей
/// </summary>
@@ -37,25 +36,43 @@ public class KeyValueList<TK, TV>: IEnumerable<KeyValue<TK, TV>>, ISerializable
/// Добавляет в список параметр
/// </summary>
/// <param name="keyValue">Параметр</param>
public void Add (KeyValue<TK, TV> keyValue) => _list.Add(keyValue);
public void Add (KeyValue<TK, TV> keyValue)
{
// Проверяет, существует ли ключ в списке
if (Contains(keyValue.Key))
ChangeValue(keyValue);
// Добавляем в список
_list.Add(keyValue);
}
/// <summary>
/// Добавляет в список параметр
/// </summary>
/// <param name="key">Ключ параметра</param>
/// <param name="value">Значение</param>
public void Add (TK key, TV value) => _list.Add(new(key, value));
public void Add (TK key, TV value) => Add(new(key, value));
/// <summary>
/// Добавляет в список некоторый набор элементов
/// </summary>
/// <param name="list">Некоторый набор элементов</param>
public void AddRange (IEnumerable<KeyValue<TK, TV>> list) => _list.AddRange(list);
public void AddRange (IEnumerable<KeyValue<TK, TV>> list)
{
// Получаю список
List<KeyValue<TK, TV>> keyValues = list.ToList();
// Для каждого элемента списка
foreach (KeyValue<TK, TV> keyValue in keyValues)
// - добавляю его в список
Add(keyValue);
}
/// <summary>
/// Изменяет значение
/// </summary>
/// <param name="keyValue">Новое значение</param>
// ReSharper disable once MemberCanBePrivate.Global
public void ChangeValue (KeyValue<TK, TV> keyValue)
{
// Если такой ключ не существует
@@ -90,6 +107,7 @@ public class KeyValueList<TK, TV>: IEnumerable<KeyValue<TK, TV>>, ISerializable
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Элемент <see cref="KeyValue{TK,TV}"/></returns>
// ReSharper disable once MemberCanBePrivate.Global
public KeyValue<TK, TV>? GetItem (TK key)
{
// Ищем элемент в списке
@@ -125,6 +143,7 @@ public class KeyValueList<TK, TV>: IEnumerable<KeyValue<TK, TV>>, ISerializable
/// Удаляет элемент из списка
/// </summary>
/// <param name="keyValue">Элемент</param>
// ReSharper disable once MemberCanBePrivate.Global
public void Remove (KeyValue<TK, TV> keyValue) => _list.Remove(keyValue);
/// <summary>
@@ -138,6 +157,7 @@ public class KeyValueList<TK, TV>: IEnumerable<KeyValue<TK, TV>>, ISerializable
/// </summary>
/// <param name="keyValue">Элемент</param>
/// <returns>Результат проверки</returns>
// ReSharper disable once MemberCanBePrivate.Global
public bool Contains (KeyValue<TK, TV> keyValue) => _list.Contains(keyValue);
/// <summary>
@@ -146,6 +166,7 @@ public class KeyValueList<TK, TV>: IEnumerable<KeyValue<TK, TV>>, ISerializable
/// <param name="key">Ключ элемента</param>
/// <returns>Результат проверки</returns>
// ReSharper disable once NullableWarningSuppressionIsUsed
// ReSharper disable once MemberCanBePrivate.Global
public bool Contains (TK key) => Keys.Any(keyParam => keyParam!.Equals(key));
/// <summary>
@@ -184,14 +205,14 @@ public class KeyValueList<TK, TV>: IEnumerable<KeyValue<TK, TV>>, ISerializable
result.AddRange(_list.Select(static item => item.Serialize()));
// Вывожу результат
return new SysTextSerializer().Serialize(result);
return new NewtonsoftJsonSerializer().Serialize(result);
}
/// <inheritdoc />
public void Deserialize (string json)
{
// Создаю результат
List<string> result = new SysTextSerializer().Deserialize<List<string>>(json) ?? [];
List<string> result = new NewtonsoftJsonSerializer().Deserialize<List<string>>(json) ?? [];
// Очищаю список
_list.Clear();

View File

@@ -0,0 +1,222 @@
using System.Collections;
using anbs_cp.Interfaces;
using anbs_cp.Structs;
namespace anbs_cp.Classes;
/// <summary>
/// Упорядоченный список из пары ключ-значение
/// </summary>
/// <typeparam name="TV">Тип значения</typeparam>
// ReSharper disable once ClassCanBeSealed.Global
public class KeyValueOrderedList<TV>: IEnumerable<KeyValueOrdered<TV>>, ISerializable
{
/// <summary>
/// Хранение значений
/// </summary>
private readonly SortedSet<KeyValueOrdered<TV>> _list = [];
#region Свойства
/// <summary>
/// Список ключей из списка
/// </summary>
public IEnumerable<string> Keys => GetKeys();
#endregion
#region Методы
/// <summary>
/// Получает список ключей
/// </summary>
/// <returns>Список ключей</returns>
private IEnumerable<string> GetKeys () => from keyValue in _list where keyValue.Key is not null select keyValue.Key;
/// <summary>
/// Добавляет в список параметр
/// </summary>
/// <param name="keyValue">Параметр</param>
public void Add (KeyValueOrdered<TV> keyValue)
{
// Проверяет, существует ли ключ в списке
if (Contains(keyValue.Key))
ChangeValue(keyValue);
// Добавляем в список
_list.Add(keyValue);
}
/// <summary>
/// Добавляет в список параметр
/// </summary>
/// <param name="key">Ключ параметра</param>
/// <param name="value">Значение</param>
public void Add (string key, TV value) => Add(new(key, value));
/// <summary>
/// Добавляет в список некоторый набор элементов
/// </summary>
/// <param name="list">Некоторый набор элементов</param>
public void AddRange (IEnumerable<KeyValueOrdered<TV>> list)
{
// Получаю список
List<KeyValueOrdered<TV>> keyValues = list.ToList();
// Для каждого элемента списка
foreach (KeyValueOrdered<TV> keyValue in keyValues)
// - добавляю его в список
Add(keyValue);
}
/// <summary>
/// Изменяет значение
/// </summary>
/// <param name="keyValue">Новое значение</param>
// ReSharper disable once MemberCanBePrivate.Global
public void ChangeValue (KeyValueOrdered<TV> keyValue)
{
// Если такой ключ не существует
if (!Contains(keyValue.Key))
{
// - тогда добавляю новое значение
Add(keyValue);
// - прерываю
return;
}
// Удаляем существующее
_list.RemoveWhere(item => item.Key == keyValue.Key);
// Добавляем новое
_list.Add(keyValue);
}
/// <summary>
/// Изменяет значение
/// </summary>
/// <param name="key">Ключ</param>
/// <param name="newValue">Новое значение</param>
public void ChangeValue (string key, TV newValue) => ChangeValue(new(key, newValue));
/// <summary>
/// Получает элемент по ключу
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Элемент <see cref="KeyValue{TK,TV}"/></returns>
// ReSharper disable once MemberCanBePrivate.Global
public KeyValueOrdered<TV>? GetItem (string key)
{
// Ищем элемент в списке
foreach (KeyValueOrdered<TV> keyValueItem in _list.Where(item => item.Key == key))
// - возвращаем его при нахождении
return keyValueItem;
// Элемент не найден -- вывожу null
return null;
}
/// <summary>
/// Получает значение
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Значение</returns>
public TV? GetValue (string key)
{
// Если такой ключ не существует
if (!Contains(key))
// Тогда возвращаю значение по умолчанию
return default;
// Получаю элемент
KeyValueOrdered<TV> keyValue = GetItem(key) ?? new();
// Вывожу значение
return keyValue.Value;
}
/// <summary>
/// Удаляет элемент из списка
/// </summary>
/// <param name="keyValue">Элемент</param>
// ReSharper disable once MemberCanBePrivate.Global
public void Remove (KeyValueOrdered<TV> keyValue) => _list.Remove(keyValue);
/// <summary>
/// Удаляет элемент из списка
/// </summary>
/// <param name="key">Ключ элемента</param>
public void Remove (string key) => Remove(GetItem(key) ?? new());
/// <summary>
/// Проверяет, содержится ли элемент в списке
/// </summary>
/// <param name="keyValue">Элемент</param>
/// <returns>Результат проверки</returns>
// ReSharper disable once MemberCanBePrivate.Global
public bool Contains (KeyValueOrdered<TV> keyValue) => _list.Contains(keyValue);
/// <summary>
/// Проверяет, содержится ли элемент в списке
/// </summary>
/// <param name="key">Ключ элемента</param>
/// <returns>Результат проверки</returns>
// ReSharper disable once NullableWarningSuppressionIsUsed
// ReSharper disable once MemberCanBePrivate.Global
public bool Contains (string key) => Keys.Any(keyName => keyName == key);
/// <summary>
/// Очистка списка
/// </summary>
public void Clear ()
{
// Очищаю список
_list.Clear();
}
#endregion
#region Реализация интерфейса IEnumerable<KeyValue<TK, TV>>
/// <inheritdoc />
public IEnumerator<KeyValueOrdered<TV>> GetEnumerator () => _list.GetEnumerator();
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator () => GetEnumerator();
#endregion
#region Реализация интерфейса ISerializable
/// <inheritdoc />
public string Serialize ()
{
// Создаю результат
List<string> result = [];
// Добавляю сериализованные значения
result.AddRange(_list.Select(static item => item.Serialize()));
// Вывожу результат
return new NewtonsoftJsonSerializer().Serialize(result);
}
/// <inheritdoc />
public void Deserialize (string json)
{
// Создаю результат
List<string> result = new NewtonsoftJsonSerializer().Deserialize<List<string>>(json) ?? [];
// Очищаю список
_list.Clear();
// Пробегаю все значения
foreach (string itemString in result)
{
// - создаю новое значение
KeyValueOrdered<TV> item = new();
// - десериализую в него элемента
item.Deserialize(itemString);
// - добавляю получившееся в список
_list.Add(item);
}
}
#endregion
}

View File

@@ -32,7 +32,7 @@ public static class LikeDelphi
/// <param name="str">Строка, которую нужно разбить</param>
/// <param name="delimiter">Символ-делитель строки</param>
/// <returns>Массив строк</returns>
public static List<string> ParseString (string str, char delimiter) => str.Split(delimiter).ToList();
public static List<string> ParseString (string str, char delimiter) => [.. str.Split(delimiter)];
/// <summary>
/// Переименовываю файл

View File

@@ -0,0 +1,27 @@
namespace anbs_cp.Enums;
/// <summary>
/// Трансформация текста
/// </summary>
public enum ETextTransform
{
/// <summary>
/// Как оригинал
/// </summary>
None = 0,
/// <summary>
/// Все буквы строчные (аналог ToLower)
/// </summary>
LowerCase = 1,
/// <summary>
/// Все буквы прописные (аналог ToUpper)
/// </summary>
UpperCase = 2,
/// <summary>
/// Первая буква заглавная, а остальные строчные
/// </summary>
FirstUpper = 3
}

View File

@@ -35,6 +35,13 @@ public static class FileExtension
public static FileHash GetHash (string fileName) =>
new(fileName);
/// <summary>
/// Получение содержимого файла
/// </summary>
/// <param name="fileName">Имя файла</param>
/// <returns>Содержимое файла</returns>
public static byte[] GetFileContent (string fileName) => File.ReadAllBytes(fileName);
#region Write
/// <summary>
/// Записывает данные <paramref name="data"/> в текстовый файл <paramref name="fileName"/>

View File

@@ -20,4 +20,50 @@ public static class GuidExtensions
/// <param name="g">Guid</param>
/// <returns>Guid пуст (null) или равен Guid.Empty</returns>
public static bool IsNullOrEmpty (this Guid g) => g == Guid.Empty;
/// <summary>
/// Генерирует <see cref="Guid"/>, удовлетворяющий условию <paramref name="predicate"/>
/// </summary>
/// <param name="predicate">Условие генерации <see cref="Guid"/></param>
/// <returns>Новый <see cref="Guid"/></returns>
public static Guid GenerateGuid (Func<Guid, bool> predicate)
{
// Задаю GUID
Guid guid;
// Выполняй
do
{
// - генерируй GUID
guid = Guid.NewGuid();
}
// - пока не выполнено условие
while (!predicate(guid));
// Возвращаю сгенерированный GUID
return guid;
}
/// <summary>
/// Генерирует <see cref="Guid"/>, удовлетворяющий условию <paramref name="asyncPredicate"/>
/// </summary>
/// <param name="asyncPredicate">Условие генерации <see cref="Guid"/></param>
/// <returns>Новый <see cref="Guid"/></returns>
public static async Task<Guid> GenerateGuidAsync (Func<Guid, Task<bool>> asyncPredicate)
{
// Задаю GUID
Guid guid;
// Выполняй
do
{
// - генерируй GUID
guid = Guid.NewGuid();
}
// - пока не выполнено условие
while (!await asyncPredicate(guid));
// Возвращаю сгенерированный GUID
return guid;
}
}

View File

@@ -1,5 +1,8 @@
using System.Diagnostics.CodeAnalysis;
using anbs_cp.Classes;
using anbs_cp.Enums;
namespace anbs_cp.Extensions;
/// <summary>
@@ -13,4 +16,78 @@ public static class StringExtensions
/// <param name="s">Строка</param>
/// <returns>Строка пуста (null) или содержит только пробелы</returns>
public static bool IsNullOrWhiteSpace ([NotNullWhen(false)] this string? s) => s == null || s.Trim().Length == 0;
/// <summary>
/// Преобразует текстовое имя параметра перечисления <see cref="T"/> в элемент перечисления.
/// Если такой элемент не найден или при ошибке перевода вернётся элемент по умолчанию <paramref name="defaultValue"/>.
/// </summary>
/// <param name="s">Строка</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <typeparam name="T">Тип перечисления</typeparam>
/// <returns>Элемент перечисления <see cref="T"/></returns>
public static T ParseToEnum<T> (this string s, T defaultValue)
{
try
{
return (T)Enum.Parse(typeof(T), s, true);
}
catch (ArgumentException)
{
return defaultValue;
}
}
/// <summary>
/// Приводит строку <paramref name="s"/> к виду "Первая буква заглавная, а все остальные -- строчные"
/// </summary>
/// <param name="s">Строка для перевода</param>
/// <returns>Приведённая строка</returns>
public static string ToFirstUpperCase (this string s)
{
// Если строка пуста
if (s.IsNullOrWhiteSpace())
// - то возвращаю её
return s;
// Задаю результат и устанавливаю первую букву заглавной
string result = $"{s[0]}".ToUpper();
// Если длина s больше, чем 1 символ
if (s.Length > 1)
// - то добавляю в результат оставшиеся символы, приведя их к LowerCase
result += s[1..].ToLower();
// Вывожу результат
return result;
}
/// <summary>
/// Трансформация текста <paramref name="s"/> по правилам <paramref name="type"/>
/// </summary>
/// <param name="s">Текст</param>
/// <param name="type">Правила преобразования</param>
/// <returns>Преобразованный текст</returns>
public static string Transform (this string s, ETextTransform type) =>
type switch
{
ETextTransform.None => s,
ETextTransform.LowerCase => s.ToLower(),
ETextTransform.UpperCase => s.ToUpper(),
ETextTransform.FirstUpper => s.ToFirstUpperCase(),
var _ => s
};
/// <summary>
/// Форматирует строку <paramref name="s"/>, заменяя все совпадения
/// по ключам из <paramref name="replaceList"/> соответствующими значениями из <paramref name="replaceList"/>.
/// Т.е. например, исходная строка «Мой дядя #Name был самых честных правил», массив замен содержал строку
/// «#Name» => «Юра», в итоге будет «Мой дядя Юра был самых честных правил».
/// </summary>
/// <param name="s">Строка для замены</param>
/// <param name="replaceList">Список замен</param>
/// <param name="comparisonType">Региональные параметры, регистр и правила сортировки</param>
/// <returns>Заменённая строка</returns>
public static string Format (this string s, KeyValueOrderedList<string> replaceList,
StringComparison comparisonType = StringComparison.CurrentCulture) => replaceList.Aggregate(s,
(current, replaceItem) => current.Replace(replaceItem.Key, replaceItem.Value, comparisonType));
}

View File

@@ -1,8 +1,7 @@
using anbs_cp.Classes;
using anbs_cp.Enums;
using anbs_cp.Exceptions;
using ISerializable = anbs_cp.Interfaces.ISerializable;
using anbs_cp.Interfaces;
namespace anbs_cp.Structs;
@@ -11,21 +10,22 @@ namespace anbs_cp.Structs;
/// </summary>
/// <typeparam name="TK">Тип ключа</typeparam>
/// <typeparam name="TV">Тип значения</typeparam>
/// <param name="key">Ключ</param>
/// <param name="value">Значение</param>
public struct KeyValue<TK, TV> (TK key, TV? value): ISerializable
/// <param name="Key">Ключ</param>
/// <param name="Value">Значение</param>
public record struct KeyValue<TK, TV> (TK Key, TV? Value): ISerializable
{
#region Свойства
/// <summary>
/// Ключ
/// </summary>
public TK Key { get; set; } = key;
public TK Key { get; private set; } = Key;
/// <summary>
/// Значение
/// </summary>
public TV? Value { get; set; } = value;
// ReSharper disable once MemberCanBePrivate.Global
public TV? Value { get; set; } = Value;
#endregion
@@ -40,17 +40,18 @@ public struct KeyValue<TK, TV> (TK key, TV? value): ISerializable
#endregion
#region Реализация интерфейса ISerializable
/// <inheritdoc />
public readonly string Serialize ()
{
// Получаю serialized-значение ключа
string keySerialized = new SysTextSerializer().Serialize(Key);
string keySerialized = new NewtonsoftJsonSerializer().Serialize(Key);
// Исключаю из этого значения = (заменяя на %EQ%)
keySerialized = keySerialized.Replace("=", "%EQ%");
// Получаю serialized-значение значения
string valueSerialized = new SysTextSerializer().Serialize(Value);
string valueSerialized = new NewtonsoftJsonSerializer().Serialize(Value);
// Исключаю из этого значения = (заменяя на %EQ%)
valueSerialized = valueSerialized.Replace("=", "%EQ%");
@@ -71,16 +72,16 @@ public struct KeyValue<TK, TV> (TK key, TV? value): ISerializable
"Неверное количество частей! Наверное, лишнее =?");
// Получаю сериализованное представление ключа
string keySerialized = splited[0].Replace("%EQ%", "=");
string keySerialized = splited[0].Replace("%EQ%", "=");
// Получаю сериализованное представление значения
// Получаю сериализованное представление значения
string valueSerialized = splited[1].Replace("%EQ%", "=");
// Десериализую ключ
Key = (new SysTextSerializer().Deserialize<TK>(keySerialized) ?? default(TK))!;
Key = (new NewtonsoftJsonSerializer().Deserialize<TK>(keySerialized) ?? default(TK))!;
// Десериализую значение
Value = new SysTextSerializer().Deserialize<TV>(valueSerialized);
Value = new NewtonsoftJsonSerializer().Deserialize<TV>(valueSerialized);
}
#endregion

View File

@@ -0,0 +1,106 @@
using anbs_cp.Classes;
using anbs_cp.Enums;
using anbs_cp.Exceptions;
using anbs_cp.Interfaces;
namespace anbs_cp.Structs;
/// <summary>
/// Упорядоченная пара ключ-значение
/// </summary>
/// <typeparam name="TValue">Тип значения</typeparam>
/// <param name="key">Ключ</param>
/// <param name="value">Значение</param>
public struct KeyValueOrdered<TValue> (string key, TValue? value): ISerializable, IComparable<KeyValueOrdered<TValue>>
{
#region Свойства
/// <summary>
/// Ключ
/// </summary>
public string Key { get; private set; } = key;
/// <summary>
/// Значение
/// </summary>
// ReSharper disable once MemberCanBePrivate.Global
public TValue? Value { get; set; } = value;
#endregion
#region Методы
/// <summary>
/// Получает ключ-значение по умолчанию
/// </summary>
/// <returns>Ключ-значение по умолчанию</returns>
public static KeyValueOrdered<TValue> GetDefault () => new();
#endregion
#region Конвертация в KeyValue<TKey, TValue>
/// <summary>
/// Переводит тип <see cref="KeyValueOrdered{TValue}"/> в тип <see cref="KeyValue{TK,TV}"/>
/// </summary>
/// <param name="keyValue">Тип <see cref="KeyValueOrdered{TValue}"/></param>
/// <returns>Тип <see cref="KeyValue{TK,TV}"/></returns>
public static KeyValue<string, TValue> ToKeyValue (KeyValueOrdered<TValue> keyValue) =>
new(keyValue.Key, keyValue.Value);
/// <summary>
/// Переводит тип <see cref="KeyValue{TK,TV}"/> в тип <see cref="KeyValueOrdered{TValue}"/>
/// </summary>
/// <param name="keyValue">Тип <see cref="KeyValue{TK,TV}"/></param>
/// <returns>Тип <see cref="KeyValueOrdered{TValue}"/></returns>
public static KeyValueOrdered<TValue> ToOrderedKeyValue (KeyValue<string, TValue> keyValue) =>
new(keyValue.Key, keyValue.Value);
#endregion
#region Реализация интерфейса ISerializable
/// <inheritdoc />
public readonly string Serialize ()
{
// Получаю serialized-значение ключа
string keySerialized = Key;
// Исключаю из этого значения = (заменяя на %EQ%)
keySerialized = keySerialized.Replace("=", "%EQ%");
// Получаю serialized-значение значения
string valueSerialized = new NewtonsoftJsonSerializer().Serialize(Value);
// Исключаю из этого значения = (заменяя на %EQ%)
valueSerialized = valueSerialized.Replace("=", "%EQ%");
// Вывожу результат
return $"{keySerialized}={valueSerialized}";
}
/// <inheritdoc />
public void Deserialize (string json)
{
// Разделяю сериализованную строку вида КЛЮЧ=ЗНАЧЕНИЕ на ключ и значение
string[] splited = json.Split('=');
// Проверяю количество частей (должно быть 2)
if (splited.Length != 2)
throw new SerializeException(ESerializeExceptionAction.Deserialize, json,
"Неверное количество частей! Наверное, лишнее =?");
// Получаю сериализованное представление ключа
string keySerialized = splited[0].Replace("%EQ%", "=");
// Получаю сериализованное представление значения
string valueSerialized = splited[1].Replace("%EQ%", "=");
// Десериализую ключ
Key = keySerialized;
// Десериализую значение
Value = new NewtonsoftJsonSerializer().Deserialize<TValue>(valueSerialized);
}
#endregion
#region Реализация интерфейса IComparable<KeyValueOrdered<TValue>>
/// <inheritdoc />
public int CompareTo (KeyValueOrdered<TValue> other) =>
// ReSharper disable once SuspiciousTypeConversion.Global
string.Compare(Key, other.Key, StringComparison.CurrentCultureIgnoreCase);
#endregion
}

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>2024.4.8</Version>
<Version>2024.8.18</Version>
<Authors>Александр Бабаев</Authors>
<Product>Набор компонентов ANB Software</Product>
<Description>Библиотека полезных методов языка C#</Description>