diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..f46f140
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,4 @@
+[*.cs]
+
+# SYSLIB1045: Преобразовать в "GeneratedRegexAttribute".
+dotnet_diagnostic.SYSLIB1045.severity = silent
diff --git a/README.md b/README.md
index 73e0c3e..0b1971b 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,4 @@
ANB Software Components Pack - набор полезных классов C#, которые расширяют возможности языка. Они могут использоваться в приложенях для ОС Widows и серверов на базе этой ОС.
# Лицензия
-MIIT
-
-# anbsoftware_componentspack
-some classes that extend the capabilities of the C # language
-
-# Лицензия
-
MIIT
\ No newline at end of file
diff --git a/anbs_cp/Classes/ConsoleParamsParser.cs b/anbs_cp/Classes/ConsoleParamsParser.cs
index 28c7688..3f16c9b 100644
--- a/anbs_cp/Classes/ConsoleParamsParser.cs
+++ b/anbs_cp/Classes/ConsoleParamsParser.cs
@@ -4,36 +4,44 @@
/// Обработчик параметров консоли
///
/// Параметры консоли
-public sealed class ConsoleParamsParser (IEnumerable consoleParams)
+/// Регистрозависимые ли параметры
+public sealed class ConsoleParamsParser(IEnumerable consoleParams, bool caseSensitive = true)
{
///
/// Массив параметров
///
- private readonly KeyValueList _paramsList = ParseConsoleParams(consoleParams);
+ private readonly KeyValueList _paramsList = ParseConsoleParams(consoleParams, caseSensitive);
///
/// Парсер параметров
///
/// Входящий список параметров
- ///
- private static KeyValueList ParseConsoleParams (IEnumerable paramsList)
+ /// Регистрозависимые ли параметры
+ /// Список параметров
+ private static KeyValueList ParseConsoleParams(IEnumerable paramsList,
+ bool caseSensitive = true)
{
- //Создаю список параметров
+ // Создаю список параметров
KeyValueList 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 consoleParams)
///
/// Параметр
/// Есть ли параметр в списке
- 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());
+ }
///
- /// Получает значение параметра
+ /// Проверяет наличие параметров
///
- ///
- ///
- public string? GetValue (string param) =>
- !HasParam(param) ? null : _paramsList.FirstOrDefault(keyValue => keyValue.Key == param.ToLower()).Value;
+ /// Массив параметров
+ /// Задан ли хотя бы один параметр
+ public bool HasParams(IEnumerable @params) =>
+ @params.Aggregate(false, (current, param) => current || HasParam(param));
+
+ ///
+ /// Получает значение параметра,
+ ///
+ /// Имя параметра
+ /// Значение по умолчанию
+ /// Значение параметра или значение по умолчанию
+ public string GetValue(string param, string @default = "") =>
+ !HasParam(param)
+ ? @default
+ : _paramsList.FirstOrDefault(keyValue => keyValue.Key == param.ToLower()).Value ?? @default;
+
+ ///
+ /// Получает значения параметров из списка.
+ ///
+ /// Список параметров
+ /// Список значений параметров
+ public IEnumerable GetValue(IEnumerable @params)
+ {
+ // Задаю результат
+ List result = [];
+
+ // Получаю список параметров
+ List paramsList = @params.ToList();
+
+ // Проверяю наличие параметров
+ if (!HasParams(paramsList))
+ // - если нет, возвращаю значение по умолчанию
+ return [];
+
+ // Для каждого параметра, если задано значение - добавляю его в результат
+ result.AddRange(paramsList.Where(HasParam).Select(param => GetValue(param))
+ .Where(value => !string.IsNullOrWhiteSpace(value)));
+
+ // Возвращаю результат
+ return result;
+ }
+
+ ///
+ /// Получает значение первого заданного параметра и возвращает значение по умолчанию, если ни один из параметров не задан.
+ ///
+ /// Список параметров
+ /// Значение по умолчанию
+ /// Значение первого заданного параметра из списка или значение по умолчанию
+ public string GetValue(IEnumerable @params, string @default) =>
+ GetValue(@params).FirstOrDefault() ?? @default;
///
/// Получает список всех параметров
///
/// Список всех параметров
- public List GetParamsList () =>
+ public List GetParamsList() =>
_paramsList.Select(static keyValue => keyValue.Key.ToLower()).ToList();
}
\ No newline at end of file
diff --git a/anbs_cp/Classes/KeyValueList.cs b/anbs_cp/Classes/KeyValueList.cs
index 3f6da5c..b905b30 100644
--- a/anbs_cp/Classes/KeyValueList.cs
+++ b/anbs_cp/Classes/KeyValueList.cs
@@ -26,7 +26,6 @@ public class KeyValueList: IEnumerable>, ISerializable
#endregion
#region Методы
-
///
/// Получает список ключей
///
@@ -37,25 +36,43 @@ public class KeyValueList: IEnumerable>, ISerializable
/// Добавляет в список параметр
///
/// Параметр
- public void Add (KeyValue keyValue) => _list.Add(keyValue);
+ public void Add (KeyValue keyValue)
+ {
+ // Проверяет, существует ли ключ в списке
+ if (Contains(keyValue.Key))
+ ChangeValue(keyValue);
+
+ // Добавляем в список
+ _list.Add(keyValue);
+ }
///
/// Добавляет в список параметр
///
/// Ключ параметра
/// Значение
- public void Add (TK key, TV value) => _list.Add(new(key, value));
+ public void Add (TK key, TV value) => Add(new(key, value));
///
/// Добавляет в список некоторый набор элементов
///
/// Некоторый набор элементов
- public void AddRange (IEnumerable> list) => _list.AddRange(list);
+ public void AddRange (IEnumerable> list)
+ {
+ // Получаю список
+ List> keyValues = list.ToList();
+
+ // Для каждого элемента списка
+ foreach (KeyValue keyValue in keyValues)
+ // - добавляю его в список
+ Add(keyValue);
+ }
///
/// Изменяет значение
///
/// Новое значение
+ // ReSharper disable once MemberCanBePrivate.Global
public void ChangeValue (KeyValue keyValue)
{
// Если такой ключ не существует
@@ -90,6 +107,7 @@ public class KeyValueList: IEnumerable>, ISerializable
///
/// Ключ
/// Элемент
+ // ReSharper disable once MemberCanBePrivate.Global
public KeyValue? GetItem (TK key)
{
// Ищем элемент в списке
@@ -125,6 +143,7 @@ public class KeyValueList: IEnumerable>, ISerializable
/// Удаляет элемент из списка
///
/// Элемент
+ // ReSharper disable once MemberCanBePrivate.Global
public void Remove (KeyValue keyValue) => _list.Remove(keyValue);
///
@@ -138,6 +157,7 @@ public class KeyValueList: IEnumerable>, ISerializable
///
/// Элемент
/// Результат проверки
+ // ReSharper disable once MemberCanBePrivate.Global
public bool Contains (KeyValue keyValue) => _list.Contains(keyValue);
///
@@ -146,6 +166,7 @@ public class KeyValueList: IEnumerable>, ISerializable
/// Ключ элемента
/// Результат проверки
// ReSharper disable once NullableWarningSuppressionIsUsed
+ // ReSharper disable once MemberCanBePrivate.Global
public bool Contains (TK key) => Keys.Any(keyParam => keyParam!.Equals(key));
///
@@ -184,14 +205,14 @@ public class KeyValueList: IEnumerable>, ISerializable
result.AddRange(_list.Select(static item => item.Serialize()));
// Вывожу результат
- return new SysTextSerializer().Serialize(result);
+ return new NewtonsoftJsonSerializer().Serialize(result);
}
///
public void Deserialize (string json)
{
// Создаю результат
- List result = new SysTextSerializer().Deserialize>(json) ?? [];
+ List result = new NewtonsoftJsonSerializer().Deserialize>(json) ?? [];
// Очищаю список
_list.Clear();
diff --git a/anbs_cp/Classes/KeyValueOrderedList.cs b/anbs_cp/Classes/KeyValueOrderedList.cs
new file mode 100644
index 0000000..8735c25
--- /dev/null
+++ b/anbs_cp/Classes/KeyValueOrderedList.cs
@@ -0,0 +1,222 @@
+using System.Collections;
+
+using anbs_cp.Interfaces;
+using anbs_cp.Structs;
+
+namespace anbs_cp.Classes;
+
+///
+/// Упорядоченный список из пары ключ-значение
+///
+/// Тип значения
+// ReSharper disable once ClassCanBeSealed.Global
+public class KeyValueOrderedList: IEnumerable>, ISerializable
+{
+ ///
+ /// Хранение значений
+ ///
+ private readonly SortedSet> _list = [];
+
+ #region Свойства
+ ///
+ /// Список ключей из списка
+ ///
+ public IEnumerable Keys => GetKeys();
+ #endregion
+
+ #region Методы
+ ///
+ /// Получает список ключей
+ ///
+ /// Список ключей
+ private IEnumerable GetKeys () => from keyValue in _list where keyValue.Key is not null select keyValue.Key;
+
+ ///
+ /// Добавляет в список параметр
+ ///
+ /// Параметр
+ public void Add (KeyValueOrdered keyValue)
+ {
+ // Проверяет, существует ли ключ в списке
+ if (Contains(keyValue.Key))
+ ChangeValue(keyValue);
+
+ // Добавляем в список
+ _list.Add(keyValue);
+ }
+
+ ///
+ /// Добавляет в список параметр
+ ///
+ /// Ключ параметра
+ /// Значение
+ public void Add (string key, TV value) => Add(new(key, value));
+
+ ///
+ /// Добавляет в список некоторый набор элементов
+ ///
+ /// Некоторый набор элементов
+ public void AddRange (IEnumerable> list)
+ {
+ // Получаю список
+ List> keyValues = list.ToList();
+
+ // Для каждого элемента списка
+ foreach (KeyValueOrdered keyValue in keyValues)
+ // - добавляю его в список
+ Add(keyValue);
+ }
+
+ ///
+ /// Изменяет значение
+ ///
+ /// Новое значение
+ // ReSharper disable once MemberCanBePrivate.Global
+ public void ChangeValue (KeyValueOrdered keyValue)
+ {
+ // Если такой ключ не существует
+ if (!Contains(keyValue.Key))
+ {
+ // - тогда добавляю новое значение
+ Add(keyValue);
+
+ // - прерываю
+ return;
+ }
+
+ // Удаляем существующее
+ _list.RemoveWhere(item => item.Key == keyValue.Key);
+
+ // Добавляем новое
+ _list.Add(keyValue);
+ }
+
+ ///
+ /// Изменяет значение
+ ///
+ /// Ключ
+ /// Новое значение
+ public void ChangeValue (string key, TV newValue) => ChangeValue(new(key, newValue));
+
+ ///
+ /// Получает элемент по ключу
+ ///
+ /// Ключ
+ /// Элемент
+ // ReSharper disable once MemberCanBePrivate.Global
+ public KeyValueOrdered? GetItem (string key)
+ {
+ // Ищем элемент в списке
+ foreach (KeyValueOrdered keyValueItem in _list.Where(item => item.Key == key))
+ // - возвращаем его при нахождении
+ return keyValueItem;
+
+ // Элемент не найден -- вывожу null
+ return null;
+ }
+
+ ///
+ /// Получает значение
+ ///
+ /// Ключ
+ /// Значение
+ public TV? GetValue (string key)
+ {
+ // Если такой ключ не существует
+ if (!Contains(key))
+ // Тогда возвращаю значение по умолчанию
+ return default;
+
+ // Получаю элемент
+ KeyValueOrdered keyValue = GetItem(key) ?? new();
+
+ // Вывожу значение
+ return keyValue.Value;
+ }
+
+ ///
+ /// Удаляет элемент из списка
+ ///
+ /// Элемент
+ // ReSharper disable once MemberCanBePrivate.Global
+ public void Remove (KeyValueOrdered keyValue) => _list.Remove(keyValue);
+
+ ///
+ /// Удаляет элемент из списка
+ ///
+ /// Ключ элемента
+ public void Remove (string key) => Remove(GetItem(key) ?? new());
+
+ ///
+ /// Проверяет, содержится ли элемент в списке
+ ///
+ /// Элемент
+ /// Результат проверки
+ // ReSharper disable once MemberCanBePrivate.Global
+ public bool Contains (KeyValueOrdered keyValue) => _list.Contains(keyValue);
+
+ ///
+ /// Проверяет, содержится ли элемент в списке
+ ///
+ /// Ключ элемента
+ /// Результат проверки
+ // ReSharper disable once NullableWarningSuppressionIsUsed
+ // ReSharper disable once MemberCanBePrivate.Global
+ public bool Contains (string key) => Keys.Any(keyName => keyName == key);
+
+ ///
+ /// Очистка списка
+ ///
+ public void Clear ()
+ {
+ // Очищаю список
+ _list.Clear();
+ }
+ #endregion
+
+ #region Реализация интерфейса IEnumerable>
+ ///
+ public IEnumerator> GetEnumerator () => _list.GetEnumerator();
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator () => GetEnumerator();
+ #endregion
+
+ #region Реализация интерфейса ISerializable
+ ///
+ public string Serialize ()
+ {
+ // Создаю результат
+ List result = [];
+
+ // Добавляю сериализованные значения
+ result.AddRange(_list.Select(static item => item.Serialize()));
+
+ // Вывожу результат
+ return new NewtonsoftJsonSerializer().Serialize(result);
+ }
+
+ ///
+ public void Deserialize (string json)
+ {
+ // Создаю результат
+ List result = new NewtonsoftJsonSerializer().Deserialize>(json) ?? [];
+
+ // Очищаю список
+ _list.Clear();
+
+ // Пробегаю все значения
+ foreach (string itemString in result)
+ {
+ // - создаю новое значение
+ KeyValueOrdered item = new();
+
+ // - десериализую в него элемента
+ item.Deserialize(itemString);
+
+ // - добавляю получившееся в список
+ _list.Add(item);
+ }
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/anbs_cp/Classes/LikeDelphi.cs b/anbs_cp/Classes/LikeDelphi.cs
index fb938d0..b2166b1 100644
--- a/anbs_cp/Classes/LikeDelphi.cs
+++ b/anbs_cp/Classes/LikeDelphi.cs
@@ -32,7 +32,7 @@ public static class LikeDelphi
/// Строка, которую нужно разбить
/// Символ-делитель строки
/// Массив строк
- public static List ParseString (string str, char delimiter) => str.Split(delimiter).ToList();
+ public static List ParseString (string str, char delimiter) => [.. str.Split(delimiter)];
///
/// Переименовываю файл
diff --git a/anbs_cp/Enums/ETextTransform.cs b/anbs_cp/Enums/ETextTransform.cs
new file mode 100644
index 0000000..57a6e19
--- /dev/null
+++ b/anbs_cp/Enums/ETextTransform.cs
@@ -0,0 +1,27 @@
+namespace anbs_cp.Enums;
+
+///
+/// Трансформация текста
+///
+public enum ETextTransform
+{
+ ///
+ /// Как оригинал
+ ///
+ None = 0,
+
+ ///
+ /// Все буквы строчные (аналог ToLower)
+ ///
+ LowerCase = 1,
+
+ ///
+ /// Все буквы прописные (аналог ToUpper)
+ ///
+ UpperCase = 2,
+
+ ///
+ /// Первая буква заглавная, а остальные строчные
+ ///
+ FirstUpper = 3
+}
\ No newline at end of file
diff --git a/anbs_cp/Extensions/FileExtensions.cs b/anbs_cp/Extensions/FileExtensions.cs
index 06cb751..8a7808c 100644
--- a/anbs_cp/Extensions/FileExtensions.cs
+++ b/anbs_cp/Extensions/FileExtensions.cs
@@ -35,6 +35,13 @@ public static class FileExtension
public static FileHash GetHash (string fileName) =>
new(fileName);
+ ///
+ /// Получение содержимого файла
+ ///
+ /// Имя файла
+ /// Содержимое файла
+ public static byte[] GetFileContent (string fileName) => File.ReadAllBytes(fileName);
+
#region Write
///
/// Записывает данные в текстовый файл
diff --git a/anbs_cp/Extensions/GuidExtensions.cs b/anbs_cp/Extensions/GuidExtensions.cs
index a7ad383..9dcdc3e 100644
--- a/anbs_cp/Extensions/GuidExtensions.cs
+++ b/anbs_cp/Extensions/GuidExtensions.cs
@@ -20,4 +20,50 @@ public static class GuidExtensions
/// Guid
/// Guid пуст (null) или равен Guid.Empty
public static bool IsNullOrEmpty (this Guid g) => g == Guid.Empty;
+
+ ///
+ /// Генерирует , удовлетворяющий условию
+ ///
+ /// Условие генерации
+ /// Новый
+ public static Guid GenerateGuid (Func predicate)
+ {
+ // Задаю GUID
+ Guid guid;
+
+ // Выполняй
+ do
+ {
+ // - генерируй GUID
+ guid = Guid.NewGuid();
+ }
+ // - пока не выполнено условие
+ while (!predicate(guid));
+
+ // Возвращаю сгенерированный GUID
+ return guid;
+ }
+
+ ///
+ /// Генерирует , удовлетворяющий условию
+ ///
+ /// Условие генерации
+ /// Новый
+ public static async Task GenerateGuidAsync (Func> asyncPredicate)
+ {
+ // Задаю GUID
+ Guid guid;
+
+ // Выполняй
+ do
+ {
+ // - генерируй GUID
+ guid = Guid.NewGuid();
+ }
+ // - пока не выполнено условие
+ while (!await asyncPredicate(guid));
+
+ // Возвращаю сгенерированный GUID
+ return guid;
+ }
}
\ No newline at end of file
diff --git a/anbs_cp/Extensions/StringExtensions.cs b/anbs_cp/Extensions/StringExtensions.cs
index 10fa67c..3a7a059 100644
--- a/anbs_cp/Extensions/StringExtensions.cs
+++ b/anbs_cp/Extensions/StringExtensions.cs
@@ -1,5 +1,8 @@
using System.Diagnostics.CodeAnalysis;
+using anbs_cp.Classes;
+using anbs_cp.Enums;
+
namespace anbs_cp.Extensions;
///
@@ -13,4 +16,78 @@ public static class StringExtensions
/// Строка
/// Строка пуста (null) или содержит только пробелы
public static bool IsNullOrWhiteSpace ([NotNullWhen(false)] this string? s) => s == null || s.Trim().Length == 0;
+
+ ///
+ /// Преобразует текстовое имя параметра перечисления в элемент перечисления.
+ /// Если такой элемент не найден или при ошибке перевода вернётся элемент по умолчанию .
+ ///
+ /// Строка
+ /// Значение по умолчанию
+ /// Тип перечисления
+ /// Элемент перечисления
+ public static T ParseToEnum (this string s, T defaultValue)
+ {
+ try
+ {
+ return (T)Enum.Parse(typeof(T), s, true);
+ }
+ catch (ArgumentException)
+ {
+ return defaultValue;
+ }
+ }
+
+ ///
+ /// Приводит строку к виду "Первая буква заглавная, а все остальные -- строчные"
+ ///
+ /// Строка для перевода
+ /// Приведённая строка
+ 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;
+ }
+
+ ///
+ /// Трансформация текста по правилам
+ ///
+ /// Текст
+ /// Правила преобразования
+ /// Преобразованный текст
+ 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
+ };
+
+ ///
+ /// Форматирует строку , заменяя все совпадения
+ /// по ключам из соответствующими значениями из .
+ /// Т.е. например, исходная строка «Мой дядя #Name был самых честных правил», массив замен содержал строку
+ /// «#Name» => «Юра», в итоге будет «Мой дядя Юра был самых честных правил».
+ ///
+ /// Строка для замены
+ /// Список замен
+ /// Региональные параметры, регистр и правила сортировки
+ /// Заменённая строка
+ public static string Format (this string s, KeyValueOrderedList replaceList,
+ StringComparison comparisonType = StringComparison.CurrentCulture) => replaceList.Aggregate(s,
+ (current, replaceItem) => current.Replace(replaceItem.Key, replaceItem.Value, comparisonType));
}
\ No newline at end of file
diff --git a/anbs_cp/Structs/KeyValue.cs b/anbs_cp/Structs/KeyValue.cs
index b5108ba..243f835 100644
--- a/anbs_cp/Structs/KeyValue.cs
+++ b/anbs_cp/Structs/KeyValue.cs
@@ -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;
///
/// Тип ключа
/// Тип значения
-/// Ключ
-/// Значение
-public struct KeyValue (TK key, TV? value): ISerializable
+/// Ключ
+/// Значение
+public record struct KeyValue (TK Key, TV? Value): ISerializable
{
#region Свойства
///
/// Ключ
///
- public TK Key { get; set; } = key;
+ public TK Key { get; private set; } = Key;
///
/// Значение
///
- 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 key, TV? value): ISerializable
#endregion
#region Реализация интерфейса ISerializable
+
///
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 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(keySerialized) ?? default(TK))!;
+ Key = (new NewtonsoftJsonSerializer().Deserialize(keySerialized) ?? default(TK))!;
// Десериализую значение
- Value = new SysTextSerializer().Deserialize(valueSerialized);
+ Value = new NewtonsoftJsonSerializer().Deserialize(valueSerialized);
}
#endregion
diff --git a/anbs_cp/Structs/KeyValueOrdered.cs b/anbs_cp/Structs/KeyValueOrdered.cs
new file mode 100644
index 0000000..5642c96
--- /dev/null
+++ b/anbs_cp/Structs/KeyValueOrdered.cs
@@ -0,0 +1,106 @@
+using anbs_cp.Classes;
+using anbs_cp.Enums;
+using anbs_cp.Exceptions;
+using anbs_cp.Interfaces;
+
+namespace anbs_cp.Structs;
+
+///
+/// Упорядоченная пара ключ-значение
+///
+/// Тип значения
+/// Ключ
+/// Значение
+public struct KeyValueOrdered (string key, TValue? value): ISerializable, IComparable>
+{
+ #region Свойства
+ ///
+ /// Ключ
+ ///
+ public string Key { get; private set; } = key;
+
+ ///
+ /// Значение
+ ///
+ // ReSharper disable once MemberCanBePrivate.Global
+ public TValue? Value { get; set; } = value;
+ #endregion
+
+ #region Методы
+ ///
+ /// Получает ключ-значение по умолчанию
+ ///
+ /// Ключ-значение по умолчанию
+ public static KeyValueOrdered GetDefault () => new();
+ #endregion
+
+ #region Конвертация в KeyValue
+ ///
+ /// Переводит тип в тип
+ ///
+ /// Тип
+ /// Тип
+ public static KeyValue ToKeyValue (KeyValueOrdered keyValue) =>
+ new(keyValue.Key, keyValue.Value);
+
+ ///
+ /// Переводит тип в тип
+ ///
+ /// Тип
+ /// Тип
+ public static KeyValueOrdered ToOrderedKeyValue (KeyValue keyValue) =>
+ new(keyValue.Key, keyValue.Value);
+ #endregion
+
+ #region Реализация интерфейса ISerializable
+ ///
+ 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}";
+ }
+
+ ///
+ 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(valueSerialized);
+ }
+ #endregion
+
+ #region Реализация интерфейса IComparable>
+ ///
+ public int CompareTo (KeyValueOrdered other) =>
+ // ReSharper disable once SuspiciousTypeConversion.Global
+ string.Compare(Key, other.Key, StringComparison.CurrentCultureIgnoreCase);
+ #endregion
+}
\ No newline at end of file
diff --git a/anbs_cp/anbs_cp.csproj b/anbs_cp/anbs_cp.csproj
index 7e2ae4d..30168b6 100644
--- a/anbs_cp/anbs_cp.csproj
+++ b/anbs_cp/anbs_cp.csproj
@@ -2,7 +2,7 @@
net8.0
- 2024.4.8
+ 2024.8.18
Александр Бабаев
Набор компонентов ANB Software
Библиотека полезных методов языка C#
diff --git a/anbs_cpdb/anbs_cpdb.csproj b/anbs_cpdb/anbs_cpdb.csproj
index af25478..6209725 100644
--- a/anbs_cpdb/anbs_cpdb.csproj
+++ b/anbs_cpdb/anbs_cpdb.csproj
@@ -8,7 +8,7 @@
anbs_cp.Database
True
ANBSoftware.ComponentsPack.Database
- 2024.3.27
+ 2024.4.26
Александр Бабаев
Набор компонентов ANB Software для работы с БД
Библиотека полезных методов языка C# для работы с базами данных
@@ -21,7 +21,7 @@
-
+
diff --git a/anbs_cpfn/Classes/CustomValidationMessages.cs b/anbs_cpfn/Classes/CustomValidationMessages.cs
new file mode 100644
index 0000000..2647e47
--- /dev/null
+++ b/anbs_cpfn/Classes/CustomValidationMessages.cs
@@ -0,0 +1,118 @@
+using System.ComponentModel.DataAnnotations;
+
+using anbs_cp.Classes;
+using anbs_cp.ForNet.Constants;
+
+using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
+
+namespace anbs_cp.ForNet.Classes;
+
+///
+/// Кастомные сообщения валидации формы
+///
+/// Кастомный список сообщений формы
+public class CustomValidationMessages (KeyValueOrderedList? messageList): IValidationMetadataProvider
+{
+ ///
+ /// Список сообщений формы
+ ///
+ // ReSharper disable once MemberCanBePrivate.Global
+ public readonly KeyValueOrderedList MessageList = messageList ?? ValidationMessagesConstants.English;
+
+ ///
+ /// Создаёт данные для локализации сообщений валидации
+ ///
+ /// Контекст
+ public void CreateValidationMetadata (ValidationMetadataProviderContext context)
+ {
+ // Если context = null, то прерываем с ошибкой
+ ArgumentNullException.ThrowIfNull(context);
+
+ // Получаю мета-данные
+ IList