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? validators = context.ValidationMetadata.ValidatorMetadata; + + // Получаю тип модели + Type? theType = context.Key.ModelType; + + // Получаю фундаментальный тип + Type? underlyingType = Nullable.GetUnderlyingType(theType); + + // Проверяю получение и соответствие + if (theType.IsValueType && underlyingType == null && + validators.All(m => m.GetType() != typeof(RequiredAttribute))) + // - задаю валидацию + validators.Add(new RequiredAttribute()); + + // Для каждого объекта валидации + foreach (object? obj in validators) + { + // - если он не атрибут + if (obj is not ValidationAttribute attribute) + // -- то продолжаю + continue; + + // RequiredAttribute + FillErrorMessage(attribute); + + // MinLengthAttribute + FillErrorMessage(attribute); + + // MaxLengthAttribute + FillErrorMessage(attribute); + + // EmailAddressAttribute + FillErrorMessage(attribute); + + // RangeAttribute + FillErrorMessage(attribute); + + // CompareAttribute + FillErrorMessage(attribute); + + // RegularExpressionAttribute + FillErrorMessage(attribute); + + // PhoneAttribute + FillErrorMessage(attribute); + + // CreditCardAttribute + FillErrorMessage(attribute); + } + } + + /// + /// Устанавливает сообщение об ошибке валидации + /// + /// Тип атрибута валидации + /// Атрибут + private void FillErrorMessage (object attribute) where T : ValidationAttribute + { + // Проверяю на соответствие типа + if (attribute is not T validationAttribute) + // - и прерываю, если не соответствует + return; + + // Если нет сообщения об ошибке + if (validationAttribute.ErrorMessage == null && validationAttribute.ErrorMessageResourceName == null) + { + // - получаю имя аттрибута + string attributeTypeName = typeof(T).Name; + + // - если список сообщений не содержит ключа с таким именем аттрибута + if (MessageList.Keys.All(s => s != attributeTypeName)) + // -- то прерываю + return; + + // - получаю предопределённое сообщение об ошибке + string? errorMessage = MessageList.GetValue(attributeTypeName); + + // - если предопределённое сообщение пусто + if (errorMessage == null) + // -- то прерываю + return; + + // - задаю значение + validationAttribute.ErrorMessage = errorMessage; + } + } +} \ No newline at end of file diff --git a/anbs_cpfn/Constants/ValidationMessagesConstants.cs b/anbs_cpfn/Constants/ValidationMessagesConstants.cs new file mode 100644 index 0000000..7b5cb0e --- /dev/null +++ b/anbs_cpfn/Constants/ValidationMessagesConstants.cs @@ -0,0 +1,41 @@ +using anbs_cp.Classes; + +namespace anbs_cp.ForNet.Constants; + +/// +/// Сообщения валидации +/// +public static class ValidationMessagesConstants +{ + /// + /// Сообщения на русском языке + /// + public static readonly KeyValueOrderedList Russian = + [ + new("RequiredAttribute", "Поле '{0}' обязательно к заполнению."), + new("MinLengthAttribute", "Минимальная длина поля '{0}' от {1} символа(-ов)."), + new("MaxLengthAttribute", "Максимальная длина поля '{0}' до {1} символа(-ов)."), + new("EmailAddressAttribute", "Адрес email некорректен."), + new("RangeAttribute", "Значение поля '{0}' должно быть между {1} и {2}."), + new("CompareAttribute", "Значение поля '{0}' не совпадаем с требуемым."), + new("RegularExpressionAttribute", "Значение поля '{0}' не удовлетворяет шаблону."), + new ("PhoneAttribute", "Значение поля '{0}' не является номером телефона."), + new ("CreditCardAttribute", "Значение поля '{0}' не является номером кредитной карты.") + ]; + + /// + /// Сообщения на английском языке + /// + public static readonly KeyValueOrderedList English = + [ + new("RequiredAttribute", "You must fill in '{0}'."), + new("MinLengthAttribute", "Min length of '{0}' is {1}."), + new("MaxLengthAttribute", "Max length of '{0}' is {1}."), + new("EmailAddressAttribute", "Invalid email address."), + new("RangeAttribute", "The value of the field '{0}' must be between {1} and {2}."), + new("CompareAttribute", "Unmatched field '{0}' value."), + new("RegularExpressionAttribute", "Invalid field '{0}' value."), + new ("PhoneAttribute", "The value of the field '{0}' is not valid phone number."), + new ("CreditCardAttribute", "The value of the field '{0}' is not valid credit card number.") + ]; +} \ No newline at end of file diff --git a/anbs_cpfn/Extensions/FormFileExtension.cs b/anbs_cpfn/Extensions/FormFileExtension.cs new file mode 100644 index 0000000..cdebf0e --- /dev/null +++ b/anbs_cpfn/Extensions/FormFileExtension.cs @@ -0,0 +1,108 @@ +using System.Text.RegularExpressions; + +using ImageMagick; + +using Microsoft.AspNetCore.Http; + +using static System.Text.RegularExpressions.Regex; + +namespace anbs_cp.ForNet.Extensions; + +/// +/// Расширение интерфейса IFormFile +/// +public static class FormFileExtension +{ + #region Константы + /// + /// Минимальный размер изображения (в байтах) + /// + private const int ImageMinimumBytes = 512; + + /// + /// Список поддерживаемых Mime-типов + /// + private static readonly List AllowedMimeTypes = + ["image/jpg", "image/jpeg", "image/pjpeg", "image/gif", "image/x-png", "image/png"]; + + /// + /// Список поддерживаемых расширений файлов + /// + private static readonly List AllowedExtensions = [".jpg", ".png", ".gif", ".jpeg"]; + #endregion + + /// + /// Получение содержимого файла + /// + /// Файл из формы + /// Содержимое файла + public static byte[] GetFileContent (this IFormFile file) + { + // Читаем содержимое файла + using BinaryReader binaryReader = new(file.OpenReadStream()); + + // Создаю контент изображения + byte[] content = binaryReader.ReadBytes((int)file.Length); + + // Вывожу результат + return content; + } + + /// + /// Проверка, является ли файл изображением + /// + /// Файл из формы + /// Является ли файл изображением + public static bool IsImage (this IFormFile postedFile) + { + // Проверяю Mime-тип + if (!AllowedMimeTypes.Contains(postedFile.ContentType.ToLower())) + return false; + + // Проверяю расширение + if (!AllowedExtensions.Contains(Path.GetExtension(postedFile.FileName).ToLower())) + return false; + + // Пытаюсь прочитать файл и проверить первые байты + try + { + if (!postedFile.OpenReadStream().CanRead) + return false; + + // Проверяю, не меньше ли размер изображения установленного предела + if (postedFile.Length < ImageMinimumBytes) + return false; + + byte[] buffer = new byte[ImageMinimumBytes]; + int _ = postedFile.OpenReadStream().Read(buffer, 0, ImageMinimumBytes); + string content = System.Text.Encoding.UTF8.GetString(buffer); + if (IsMatch(content, + @"enable True ANBSoftware.ComponentsPackForNet - 2024.3.27 + 2024.9.1 Александр Бабаев Набор компонентов ANB Software для ASP.NET Core Библиотека полезных методов языка C# для ASP.NET Core @@ -20,20 +20,18 @@ - - + + + + - + - - - - diff --git a/anbsoftware.componentspack.sln b/anbsoftware.componentspack.sln index 0760bba..3d1a9bc 100644 --- a/anbsoftware.componentspack.sln +++ b/anbsoftware.componentspack.sln @@ -16,6 +16,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "anbs_cposinfo", "anbs_cposi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "anbs_cpdb", "anbs_cpdb\anbs_cpdb.csproj", "{3796862F-F181-4A27-92D8-8BF13C4FD711}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "demo2", "demo2\demo2.csproj", "{ED9A2B81-5060-4906-AAC4-88ED1C70211E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F9AFD424-6FCE-465A-8EEF-DA99D3350696}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -41,6 +48,10 @@ Global {3796862F-F181-4A27-92D8-8BF13C4FD711}.Debug|Any CPU.Build.0 = Debug|Any CPU {3796862F-F181-4A27-92D8-8BF13C4FD711}.Release|Any CPU.ActiveCfg = Release|Any CPU {3796862F-F181-4A27-92D8-8BF13C4FD711}.Release|Any CPU.Build.0 = Release|Any CPU + {ED9A2B81-5060-4906-AAC4-88ED1C70211E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED9A2B81-5060-4906-AAC4-88ED1C70211E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED9A2B81-5060-4906-AAC4-88ED1C70211E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED9A2B81-5060-4906-AAC4-88ED1C70211E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/anbsoftware.componentspack.sln.DotSettings b/anbsoftware.componentspack.sln.DotSettings index c30ce8d..ccecebf 100644 --- a/anbsoftware.componentspack.sln.DotSettings +++ b/anbsoftware.componentspack.sln.DotSettings @@ -5,6 +5,7 @@ IP RA RAM + URL True True True @@ -15,6 +16,8 @@ True True True + True + True True True True @@ -38,6 +41,7 @@ True True True + True True True True diff --git a/demo/MainMenu.Designer.cs b/demo/MainMenu.Designer.cs index 23417f8..c21230e 100644 --- a/demo/MainMenu.Designer.cs +++ b/demo/MainMenu.Designer.cs @@ -33,6 +33,7 @@ sealed partial class MainMenu FileExtensionTest = new Button(); OsInfoBtn = new Button(); actionStateSerializerTestBtn = new Button(); + stringExtensionTestButton = new Button(); SuspendLayout(); // // CountValueTest @@ -77,7 +78,7 @@ sealed partial class MainMenu // // actionStateSerializerTestBtn // - actionStateSerializerTestBtn.Location = new Point(12, 254); + actionStateSerializerTestBtn.Location = new Point(12, 242); actionStateSerializerTestBtn.Name = "actionStateSerializerTestBtn"; actionStateSerializerTestBtn.Size = new Size(335, 51); actionStateSerializerTestBtn.TabIndex = 4; @@ -85,11 +86,22 @@ sealed partial class MainMenu actionStateSerializerTestBtn.UseVisualStyleBackColor = true; actionStateSerializerTestBtn.Click += actionStateSerializerTestBtn_Click; // + // stringExtensionTestButton + // + stringExtensionTestButton.Location = new Point(12, 299); + stringExtensionTestButton.Name = "stringExtensionTestButton"; + stringExtensionTestButton.Size = new Size(335, 51); + stringExtensionTestButton.TabIndex = 5; + stringExtensionTestButton.Text = "Тест расширения класса string"; + stringExtensionTestButton.UseVisualStyleBackColor = true; + stringExtensionTestButton.Click += stringExtensionTestButton_Click; + // // MainMenu // AutoScaleDimensions = new SizeF(10F, 21F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(361, 327); + ClientSize = new Size(361, 361); + Controls.Add(stringExtensionTestButton); Controls.Add(actionStateSerializerTestBtn); Controls.Add(OsInfoBtn); Controls.Add(FileExtensionTest); @@ -98,7 +110,10 @@ sealed partial class MainMenu Font = new Font("Times New Roman", 14.25F); FormBorderStyle = FormBorderStyle.FixedSingle; Margin = new Padding(4); + MaximizeBox = false; + MinimizeBox = false; Name = "MainMenu"; + ShowIcon = false; StartPosition = FormStartPosition.CenterScreen; Text = "Главное меню"; ResumeLayout(false); @@ -111,4 +126,5 @@ sealed partial class MainMenu private Button FileExtensionTest; private Button OsInfoBtn; private Button actionStateSerializerTestBtn; + private Button stringExtensionTestButton; } diff --git a/demo/MainMenu.cs b/demo/MainMenu.cs index 79fd69a..d070246 100644 --- a/demo/MainMenu.cs +++ b/demo/MainMenu.cs @@ -1,4 +1,6 @@ -namespace demo; +using demo.TestForms; + +namespace demo; public sealed partial class MainMenu: Form { public MainMenu () @@ -35,4 +37,10 @@ public sealed partial class MainMenu: Form ActionStateSerialize form = new(); form.ShowDialog(); } + + private void stringExtensionTestButton_Click (object sender, EventArgs e) + { + StringExtensionTest form = new(); + form.ShowDialog(); + } } diff --git a/demo/TestForms/ActionStateSerialize.Designer.cs b/demo/TestForms/ActionStateSerialize.Designer.cs new file mode 100644 index 0000000..f9edb93 --- /dev/null +++ b/demo/TestForms/ActionStateSerialize.Designer.cs @@ -0,0 +1,92 @@ +namespace demo.TestForms; + +sealed partial class ActionStateSerialize +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose (bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent () + { + textBox1 = new TextBox(); + textBox2 = new TextBox(); + label1 = new Label(); + button1 = new Button(); + SuspendLayout(); + // + // textBox1 + // + textBox1.Location = new Point(24, 12); + textBox1.Name = "textBox1"; + textBox1.Size = new Size(209, 23); + textBox1.TabIndex = 0; + // + // textBox2 + // + textBox2.Location = new Point(312, 6); + textBox2.Multiline = true; + textBox2.Name = "textBox2"; + textBox2.Size = new Size(463, 225); + textBox2.TabIndex = 1; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(24, 65); + label1.Name = "label1"; + label1.Size = new Size(38, 15); + label1.TabIndex = 2; + label1.Text = "label1"; + // + // button1 + // + button1.Location = new Point(24, 111); + button1.Name = "button1"; + button1.Size = new Size(75, 23); + button1.TabIndex = 3; + button1.Text = "button1"; + button1.UseVisualStyleBackColor = true; + button1.Click += button1_Click; + // + // ActionStateSerialize + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(800, 250); + Controls.Add(button1); + Controls.Add(label1); + Controls.Add(textBox2); + Controls.Add(textBox1); + Name = "ActionStateSerialize"; + Text = "Тест сериализации ActionState"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private TextBox textBox1; + private TextBox textBox2; + private Label label1; + private Button button1; +} \ No newline at end of file diff --git a/demo/TestForms/ActionStateSerialize.cs b/demo/TestForms/ActionStateSerialize.cs new file mode 100644 index 0000000..70131d4 --- /dev/null +++ b/demo/TestForms/ActionStateSerialize.cs @@ -0,0 +1,34 @@ +using anbs_cp.Classes; + +namespace demo.TestForms; + +public sealed partial class ActionStateSerialize: Form +{ + public ActionStateSerialize () + { + InitializeComponent(); + } + + private void button1_Click (object sender, EventArgs e) + { + DemoClass demoClass = new() + { + Name = textBox1.Text.Length > 0 ? textBox1.Text : string.Empty + }; + + ActionState state = new() + { + Value = demoClass + }; + + state.AddError("ОШИБКА, ШЕФ!"); + + textBox2.Text = state.Serialize(); + + ActionState state2 = new(); + + state2.Deserialize(textBox2.Text); + + label1.Text = state2.Value?.Name ?? "НЕТ ЗНАЧЕНИЯ"; + } +} diff --git a/demo/TestForms/ActionStateSerialize.resx b/demo/TestForms/ActionStateSerialize.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/demo/TestForms/ActionStateSerialize.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/demo/TestForms/CountValueTest.Designer.cs b/demo/TestForms/CountValueTest.Designer.cs new file mode 100644 index 0000000..c3cf0f3 --- /dev/null +++ b/demo/TestForms/CountValueTest.Designer.cs @@ -0,0 +1,147 @@ +namespace demo.TestForms; + +sealed partial class CountValueTest +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose (bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent () + { + this.InsertDataLabel = new System.Windows.Forms.Label(); + this.InsertDataBox = new System.Windows.Forms.TextBox(); + this.ResultLabel = new System.Windows.Forms.Label(); + this.CalculateButton = new System.Windows.Forms.Button(); + this.SelectFormatterLabel = new System.Windows.Forms.Label(); + this.SelectFormatterBox = new System.Windows.Forms.ComboBox(); + this.calculateConvButton = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // InsertDataLabel + // + this.InsertDataLabel.AutoSize = true; + this.InsertDataLabel.Location = new System.Drawing.Point(12, 66); + this.InsertDataLabel.Name = "InsertDataLabel"; + this.InsertDataLabel.Size = new System.Drawing.Size(341, 17); + this.InsertDataLabel.TabIndex = 0; + this.InsertDataLabel.Text = "&Введите любое целочисленное значение:"; + // + // InsertDataBox + // + this.InsertDataBox.Location = new System.Drawing.Point(12, 86); + this.InsertDataBox.Name = "InsertDataBox"; + this.InsertDataBox.Size = new System.Drawing.Size(457, 24); + this.InsertDataBox.TabIndex = 1; + this.InsertDataBox.TextChanged += new System.EventHandler(this.InsertDataBox_TextChanged); + // + // ResultLabel + // + this.ResultLabel.Dock = System.Windows.Forms.DockStyle.Bottom; + this.ResultLabel.Location = new System.Drawing.Point(0, 143); + this.ResultLabel.Margin = new System.Windows.Forms.Padding(5); + this.ResultLabel.Name = "ResultLabel"; + this.ResultLabel.Padding = new System.Windows.Forms.Padding(5); + this.ResultLabel.Size = new System.Drawing.Size(478, 79); + this.ResultLabel.TabIndex = 2; + this.ResultLabel.Text = "&Вставьте любое целочисленное значение в поле выше и нажмите кнопку \"Вычислить\", " + + "чтобы увидеть результат..."; + this.ResultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // CalculateButton + // + this.CalculateButton.Location = new System.Drawing.Point(12, 116); + this.CalculateButton.Name = "CalculateButton"; + this.CalculateButton.Size = new System.Drawing.Size(234, 23); + this.CalculateButton.TabIndex = 3; + this.CalculateButton.Text = "В&ычислить обработчиком"; + this.CalculateButton.UseVisualStyleBackColor = true; + this.CalculateButton.Click += new System.EventHandler(this.CalculateButton_Click); + // + // SelectFormatterLabel + // + this.SelectFormatterLabel.AutoSize = true; + this.SelectFormatterLabel.Location = new System.Drawing.Point(12, 9); + this.SelectFormatterLabel.Name = "SelectFormatterLabel"; + this.SelectFormatterLabel.Size = new System.Drawing.Size(188, 17); + this.SelectFormatterLabel.TabIndex = 4; + this.SelectFormatterLabel.Text = "В&ыберете обработчик:"; + // + // SelectFormatterBox + // + this.SelectFormatterBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.SelectFormatterBox.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.SelectFormatterBox.FormattingEnabled = true; + this.SelectFormatterBox.Items.AddRange(new object[] { + "Обработчик счёта", + "Обработчик размера файла"}); + this.SelectFormatterBox.Location = new System.Drawing.Point(12, 29); + this.SelectFormatterBox.Name = "SelectFormatterBox"; + this.SelectFormatterBox.Size = new System.Drawing.Size(457, 25); + this.SelectFormatterBox.TabIndex = 5; + // + // calculateConvButton + // + this.calculateConvButton.Location = new System.Drawing.Point(252, 116); + this.calculateConvButton.Name = "calculateConvButton"; + this.calculateConvButton.Size = new System.Drawing.Size(217, 23); + this.calculateConvButton.TabIndex = 6; + this.calculateConvButton.Text = "&Вычислить конвертером"; + this.calculateConvButton.UseVisualStyleBackColor = true; + this.calculateConvButton.Click += new System.EventHandler(this.calculateConvButton_Click); + // + // CountValueTest + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(478, 222); + this.Controls.Add(this.calculateConvButton); + this.Controls.Add(this.SelectFormatterBox); + this.Controls.Add(this.SelectFormatterLabel); + this.Controls.Add(this.CalculateButton); + this.Controls.Add(this.ResultLabel); + this.Controls.Add(this.InsertDataBox); + this.Controls.Add(this.InsertDataLabel); + this.Font = new System.Drawing.Font("Courier New", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CountValueTest"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Тест модуля форматирования строки"; + this.Load += new System.EventHandler(this.CountValueTest_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label InsertDataLabel; + private TextBox InsertDataBox; + private Label ResultLabel; + private Button CalculateButton; + private Label SelectFormatterLabel; + private ComboBox SelectFormatterBox; + private Button calculateConvButton; +} \ No newline at end of file diff --git a/demo/TestForms/CountValueTest.cs b/demo/TestForms/CountValueTest.cs new file mode 100644 index 0000000..80fd324 --- /dev/null +++ b/demo/TestForms/CountValueTest.cs @@ -0,0 +1,56 @@ +using anbs_cp.Classes; +using anbs_cp.Interfaces; + +namespace demo.TestForms; + +public sealed partial class CountValueTest: Form +{ + public CountValueTest () + { + InitializeComponent(); + } + + private void CalculateButton_Click (object sender, EventArgs e) + { + + if (string.IsNullOrEmpty(InsertDataBox.Text)) + return; + + long value = TypeConverter.StrToInt64(InsertDataBox.Text); + IValueFormatter formatter = SelectFormatterBox.SelectedIndex switch + { + 0 => new CountFormatter(), + 1 => new FileSizeFormatter(), + _ => new CountFormatter(), + }; + ResultLabel.Text = formatter.Format(value); + } + + private void CountValueTest_Load (object sender, EventArgs e) + { + SelectFormatterBox.SelectedIndex = 0; + } + + private void InsertDataBox_TextChanged (object sender, EventArgs e) + { + ulong value = TypeConverter.StrToUInt64(InsertDataBox.Text); + + if (value > long.MaxValue) + InsertDataBox.Text = long.MaxValue.ToString(); + } + + private void calculateConvButton_Click (object sender, EventArgs e) + { + if (string.IsNullOrEmpty(InsertDataBox.Text)) + return; + + long value = TypeConverter.StrToInt64(InsertDataBox.Text); + + ResultLabel.Text = SelectFormatterBox.SelectedIndex switch + { + 0 => new CountConverter(CountConverter.DefaultNames).Convert(value), + 1 => new FileSizeConverter(FileSizeConverter.DefaultNames).Convert(value), + _ => new CountConverter(CountConverter.DefaultNames).Convert(value) + }; + } +} \ No newline at end of file diff --git a/demo/TestForms/CountValueTest.resx b/demo/TestForms/CountValueTest.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/demo/TestForms/CountValueTest.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/demo/TestForms/FileHashAndMimeTypeTest.Designer.cs b/demo/TestForms/FileHashAndMimeTypeTest.Designer.cs new file mode 100644 index 0000000..a341972 --- /dev/null +++ b/demo/TestForms/FileHashAndMimeTypeTest.Designer.cs @@ -0,0 +1,125 @@ +namespace demo.TestForms; + +sealed partial class FileHashAndMimeType +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose (bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent () + { + this.ResultLabel = new System.Windows.Forms.Label(); + this.SelectFileLabel = new System.Windows.Forms.Label(); + this.fileNameEdt = new System.Windows.Forms.TextBox(); + this.ViewButton = new System.Windows.Forms.Button(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.topPanel = new System.Windows.Forms.Panel(); + this.topPanel.SuspendLayout(); + this.SuspendLayout(); + // + // ResultLabel + // + this.ResultLabel.Dock = System.Windows.Forms.DockStyle.Fill; + this.ResultLabel.Location = new System.Drawing.Point(0, 0); + this.ResultLabel.Margin = new System.Windows.Forms.Padding(5); + this.ResultLabel.Name = "ResultLabel"; + this.ResultLabel.Padding = new System.Windows.Forms.Padding(5); + this.ResultLabel.Size = new System.Drawing.Size(412, 428); + this.ResultLabel.TabIndex = 2; + this.ResultLabel.Text = "В&ыберете файл (введите ипя файла с полным путём вверху или с помощью диалога, на" + + "жав \"Обзор\")..."; + this.ResultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // SelectFileLabel + // + this.SelectFileLabel.AutoSize = true; + this.SelectFileLabel.Location = new System.Drawing.Point(3, 11); + this.SelectFileLabel.Name = "SelectFileLabel"; + this.SelectFileLabel.Size = new System.Drawing.Size(134, 17); + this.SelectFileLabel.TabIndex = 4; + this.SelectFileLabel.Text = "В&ыберете файл:"; + // + // fileNameEdt + // + this.fileNameEdt.Location = new System.Drawing.Point(3, 38); + this.fileNameEdt.Name = "fileNameEdt"; + this.fileNameEdt.Size = new System.Drawing.Size(288, 24); + this.fileNameEdt.TabIndex = 5; + this.fileNameEdt.TextChanged += new System.EventHandler(this.fileNameEdt_TextChanged); + // + // ViewButton + // + this.ViewButton.Location = new System.Drawing.Point(297, 39); + this.ViewButton.Name = "ViewButton"; + this.ViewButton.Size = new System.Drawing.Size(103, 23); + this.ViewButton.TabIndex = 3; + this.ViewButton.Text = "&Обзор"; + this.ViewButton.UseVisualStyleBackColor = true; + this.ViewButton.Click += new System.EventHandler(this.ViewButton_Click); + // + // openFileDialog + // + this.openFileDialog.AddToRecent = false; + this.openFileDialog.Filter = "Все файлы|*.*"; + this.openFileDialog.FileOk += new System.ComponentModel.CancelEventHandler(this.openFileDialog_FileOk); + // + // topPanel + // + this.topPanel.Controls.Add(this.SelectFileLabel); + this.topPanel.Controls.Add(this.ViewButton); + this.topPanel.Controls.Add(this.fileNameEdt); + this.topPanel.Dock = System.Windows.Forms.DockStyle.Top; + this.topPanel.Location = new System.Drawing.Point(0, 0); + this.topPanel.Name = "topPanel"; + this.topPanel.Size = new System.Drawing.Size(412, 74); + this.topPanel.TabIndex = 6; + // + // FileHashAndMimeType + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(412, 428); + this.Controls.Add(this.topPanel); + this.Controls.Add(this.ResultLabel); + this.Font = new System.Drawing.Font("Courier New", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FileHashAndMimeType"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Получение хэша и MIME-типа файла"; + this.topPanel.ResumeLayout(false); + this.topPanel.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private Label ResultLabel; + private Label SelectFileLabel; + private TextBox fileNameEdt; + private Button ViewButton; + private OpenFileDialog openFileDialog; + private Panel topPanel; +} \ No newline at end of file diff --git a/demo/TestForms/FileHashAndMimeTypeTest.cs b/demo/TestForms/FileHashAndMimeTypeTest.cs new file mode 100644 index 0000000..8fe7b26 --- /dev/null +++ b/demo/TestForms/FileHashAndMimeTypeTest.cs @@ -0,0 +1,44 @@ +using anbs_cp.Classes; +using anbs_cp.Extensions; + +// ReSharper disable LocalizableElement + +namespace demo.TestForms; + +public sealed partial class FileHashAndMimeType: Form +{ + public FileHashAndMimeType () + { + InitializeComponent(); + } + + private void ViewButton_Click (object sender, EventArgs e) + { + openFileDialog.ShowDialog(); + } + + private void GetFileHashAndMimeType () + { + if (string.IsNullOrEmpty(fileNameEdt.Text)) + { + ResultLabel.Text = " !"; + return; + } + + string fileHash = new FileHash(fileNameEdt.Text).ToString(); + string fileType = FileExtension.MimeType(fileNameEdt.Text); + + ResultLabel.Text = + $" \r\n{fileNameEdt.Text}\r\n :\r\n{fileHash}\r\n :\r\n{fileType}"; + } + + private void openFileDialog_FileOk (object sender, System.ComponentModel.CancelEventArgs e) + { + fileNameEdt.Text = openFileDialog.FileName; + } + + private void fileNameEdt_TextChanged (object sender, EventArgs e) + { + GetFileHashAndMimeType(); + } +} \ No newline at end of file diff --git a/demo/TestForms/FileHashAndMimeTypeTest.resx b/demo/TestForms/FileHashAndMimeTypeTest.resx new file mode 100644 index 0000000..e6275bd --- /dev/null +++ b/demo/TestForms/FileHashAndMimeTypeTest.resx @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/demo/TestForms/OsInfoFrm.Designer.cs b/demo/TestForms/OsInfoFrm.Designer.cs new file mode 100644 index 0000000..85f3d43 --- /dev/null +++ b/demo/TestForms/OsInfoFrm.Designer.cs @@ -0,0 +1,65 @@ +namespace demo.TestForms; + +sealed partial class OsInfoFrm +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose (bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent () + { + this.textBox = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // textBox + // + this.textBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBox.Location = new System.Drawing.Point(0, 0); + this.textBox.Multiline = true; + this.textBox.Name = "textBox"; + this.textBox.Size = new System.Drawing.Size(1029, 510); + this.textBox.TabIndex = 0; + // + // OsInfoFrm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1029, 510); + this.Controls.Add(this.textBox); + this.Font = new System.Drawing.Font("Courier New", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D; + this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "OsInfoFrm"; + this.Text = "Информация о системе"; + this.Load += new System.EventHandler(this.OsInfoFrm_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private TextBox textBox; +} \ No newline at end of file diff --git a/demo/TestForms/OsInfoFrm.cs b/demo/TestForms/OsInfoFrm.cs new file mode 100644 index 0000000..e4bf648 --- /dev/null +++ b/demo/TestForms/OsInfoFrm.cs @@ -0,0 +1,27 @@ +using anbs_cp.Classes; +using anbs_cp.OsInfo.Classes; + +namespace demo.TestForms; +public sealed partial class OsInfoFrm: Form +{ + public OsInfoFrm () + { + InitializeComponent(); + } + + private void OsInfoFrm_Load (object sender, EventArgs e) + { + textBox.Text = @"Процессор(ы) | "; + textBox.Text += new SysTextSerializer().Serialize(OsInfo.Processors); + textBox.Text += @"Оперативная память | "; + textBox.Text += new SysTextSerializer().Serialize(OsInfo.RAM); + textBox.Text += @"Видеокарта | "; + textBox.Text += new SysTextSerializer().Serialize(OsInfo.Videos); + textBox.Text += @"Диски | "; + textBox.Text += new SysTextSerializer().Serialize(OsInfo.Drives); + textBox.Text += @"Windows | "; + textBox.Text += new SysTextSerializer().Serialize(OsInfo.Windows); + textBox.Text += @"Net | "; + textBox.Text += new SysTextSerializer().Serialize(OsInfo.Net); + } +} diff --git a/demo/TestForms/OsInfoFrm.resx b/demo/TestForms/OsInfoFrm.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/demo/TestForms/OsInfoFrm.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/demo/TestForms/SampleMapperTest.Designer.cs b/demo/TestForms/SampleMapperTest.Designer.cs new file mode 100644 index 0000000..dbca275 --- /dev/null +++ b/demo/TestForms/SampleMapperTest.Designer.cs @@ -0,0 +1,189 @@ +namespace demo.TestForms; + +sealed partial class SampleMapperTest +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose (bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent () + { + this.DemoBoolEdt = new System.Windows.Forms.CheckBox(); + this.DemoStringEdt = new System.Windows.Forms.TextBox(); + this.DemoIntEdt = new System.Windows.Forms.NumericUpDown(); + this.DemoDateTimeEdt = new System.Windows.Forms.DateTimePicker(); + this.MapBtn = new System.Windows.Forms.Button(); + this.ResultArea = new System.Windows.Forms.TextBox(); + this.DemoStringLabel = new System.Windows.Forms.Label(); + this.DemoIntLabel = new System.Windows.Forms.Label(); + this.DemoDateTimeLabel = new System.Windows.Forms.Label(); + this.MapModeEdit = new System.Windows.Forms.ComboBox(); + this.MapModeLabel = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.DemoIntEdt)).BeginInit(); + this.SuspendLayout(); + // + // DemoBoolEdt + // + this.DemoBoolEdt.AutoSize = true; + this.DemoBoolEdt.Location = new System.Drawing.Point(32, 144); + this.DemoBoolEdt.Name = "DemoBoolEdt"; + this.DemoBoolEdt.Size = new System.Drawing.Size(65, 25); + this.DemoBoolEdt.TabIndex = 0; + this.DemoBoolEdt.Text = "Bool"; + this.DemoBoolEdt.UseVisualStyleBackColor = true; + // + // DemoStringEdt + // + this.DemoStringEdt.Location = new System.Drawing.Point(32, 42); + this.DemoStringEdt.Name = "DemoStringEdt"; + this.DemoStringEdt.Size = new System.Drawing.Size(737, 29); + this.DemoStringEdt.TabIndex = 1; + // + // DemoIntEdt + // + this.DemoIntEdt.Location = new System.Drawing.Point(32, 109); + this.DemoIntEdt.Name = "DemoIntEdt"; + this.DemoIntEdt.Size = new System.Drawing.Size(737, 29); + this.DemoIntEdt.TabIndex = 2; + // + // DemoDateTimeEdt + // + this.DemoDateTimeEdt.CustomFormat = "dd.MM.yyyy HH:mm:ss"; + this.DemoDateTimeEdt.Format = System.Windows.Forms.DateTimePickerFormat.Custom; + this.DemoDateTimeEdt.Location = new System.Drawing.Point(32, 193); + this.DemoDateTimeEdt.Name = "DemoDateTimeEdt"; + this.DemoDateTimeEdt.Size = new System.Drawing.Size(737, 29); + this.DemoDateTimeEdt.TabIndex = 3; + // + // MapBtn + // + this.MapBtn.Location = new System.Drawing.Point(32, 306); + this.MapBtn.Name = "MapBtn"; + this.MapBtn.Size = new System.Drawing.Size(737, 57); + this.MapBtn.TabIndex = 5; + this.MapBtn.Text = "СВЯЗАТЬ"; + this.MapBtn.UseVisualStyleBackColor = true; + this.MapBtn.Click += new System.EventHandler(this.MapBtn_Click); + // + // ResultArea + // + this.ResultArea.Dock = System.Windows.Forms.DockStyle.Right; + this.ResultArea.Location = new System.Drawing.Point(819, 0); + this.ResultArea.Multiline = true; + this.ResultArea.Name = "ResultArea"; + this.ResultArea.ReadOnly = true; + this.ResultArea.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.ResultArea.Size = new System.Drawing.Size(332, 378); + this.ResultArea.TabIndex = 6; + // + // DemoStringLabel + // + this.DemoStringLabel.AutoSize = true; + this.DemoStringLabel.Location = new System.Drawing.Point(32, 18); + this.DemoStringLabel.Name = "DemoStringLabel"; + this.DemoStringLabel.Size = new System.Drawing.Size(54, 21); + this.DemoStringLabel.TabIndex = 7; + this.DemoStringLabel.Text = "String"; + // + // DemoIntLabel + // + this.DemoIntLabel.AutoSize = true; + this.DemoIntLabel.Location = new System.Drawing.Point(32, 85); + this.DemoIntLabel.Name = "DemoIntLabel"; + this.DemoIntLabel.Size = new System.Drawing.Size(30, 21); + this.DemoIntLabel.TabIndex = 8; + this.DemoIntLabel.Text = "Int"; + // + // DemoDateTimeLabel + // + this.DemoDateTimeLabel.AutoSize = true; + this.DemoDateTimeLabel.Location = new System.Drawing.Point(32, 169); + this.DemoDateTimeLabel.Name = "DemoDateTimeLabel"; + this.DemoDateTimeLabel.Size = new System.Drawing.Size(81, 21); + this.DemoDateTimeLabel.TabIndex = 9; + this.DemoDateTimeLabel.Text = "DateTime"; + // + // MapModeEdit + // + this.MapModeEdit.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.MapModeEdit.FormattingEnabled = true; + this.MapModeEdit.Items.AddRange(new object[] { + "Full", + "Not null", + "Not default", + "Not null or default"}); + this.MapModeEdit.Location = new System.Drawing.Point(32, 254); + this.MapModeEdit.Name = "MapModeEdit"; + this.MapModeEdit.Size = new System.Drawing.Size(737, 29); + this.MapModeEdit.TabIndex = 10; + // + // MapModeLabel + // + this.MapModeLabel.AutoSize = true; + this.MapModeLabel.Location = new System.Drawing.Point(32, 230); + this.MapModeLabel.Name = "MapModeLabel"; + this.MapModeLabel.Size = new System.Drawing.Size(167, 21); + this.MapModeLabel.TabIndex = 11; + this.MapModeLabel.Text = "Режим связывания:"; + // + // SampleMapperTest + // + this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 21F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1151, 378); + this.Controls.Add(this.MapModeLabel); + this.Controls.Add(this.MapModeEdit); + this.Controls.Add(this.DemoDateTimeLabel); + this.Controls.Add(this.DemoIntLabel); + this.Controls.Add(this.DemoStringLabel); + this.Controls.Add(this.ResultArea); + this.Controls.Add(this.MapBtn); + this.Controls.Add(this.DemoDateTimeEdt); + this.Controls.Add(this.DemoIntEdt); + this.Controls.Add(this.DemoStringEdt); + this.Controls.Add(this.DemoBoolEdt); + this.Font = new System.Drawing.Font("Times New Roman", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.Margin = new System.Windows.Forms.Padding(4); + this.Name = "SampleMapperTest"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Тест класса SampleMapper"; + ((System.ComponentModel.ISupportInitialize)(this.DemoIntEdt)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private CheckBox DemoBoolEdt; + private TextBox DemoStringEdt; + private NumericUpDown DemoIntEdt; + private DateTimePicker DemoDateTimeEdt; + private Button MapBtn; + private TextBox ResultArea; + private Label DemoStringLabel; + private Label DemoIntLabel; + private Label DemoDateTimeLabel; + private ComboBox MapModeEdit; + private Label MapModeLabel; +} diff --git a/demo/TestForms/SampleMapperTest.cs b/demo/TestForms/SampleMapperTest.cs new file mode 100644 index 0000000..b9f5ba4 --- /dev/null +++ b/demo/TestForms/SampleMapperTest.cs @@ -0,0 +1,70 @@ +using anbs_cp.Classes; + +namespace demo.TestForms; +public sealed partial class SampleMapperTest: Form +{ + public SampleMapperTest () + { + InitializeComponent(); + } + + private void MapBtn_Click (object sender, EventArgs e) + { + Demo1Class demo1 = new() + { + DemoString = DemoStringEdt.Text, + DemoInt = (int)DemoIntEdt.Value, + DemoBool = DemoBoolEdt.Checked, + DemoDateTime = DemoDateTimeEdt.Value + }; + + Demo1Class demo2 = new() + { + DemoInt = 20220224, + DemoBool = true, + DemoDateTime = default + }; + + string serialize1 = new SysTextSerializer().Serialize(demo2); + + SimpleMapper.MapMode mode = MapModeEdit.SelectedIndex switch + { + 0 => SimpleMapper.MapMode.MapFull, + 1 => SimpleMapper.MapMode.MapNotNull, + 2 => SimpleMapper.MapMode.MapNotDefault, + 3 => SimpleMapper.MapMode.MapNotNullOrDefault, + _ => SimpleMapper.MapMode.MapFull + }; + + SimpleMapper.MapEx(demo1, ref demo2, mode, new List()); + + string serialize2 = new SysTextSerializer().Serialize(demo2); + + // ReSharper disable once LocalizableElement + ResultArea.Text = $"Класс Demo2 до связывания:\r\n{serialize1}\r\nи после:\r\n{serialize2}"; + } +} + +public sealed class Demo1Class +{ + public string? DemoString { get; set; } + + public int DemoInt { get; set; } + + public bool DemoBool { get; set; } + + public DateTime DemoDateTime { get; set; } +} + +public class Demo2Class +{ + public string? DemoString { get; set; } + + public int DemoInt { get; set; } + + public bool DemoBool { get; set; } + + public DateTime DemoDateTime { get; set; } + + public string? DemoStringNotMapped { get; set; } +} \ No newline at end of file diff --git a/demo/TestForms/SampleMapperTest.resx b/demo/TestForms/SampleMapperTest.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/demo/TestForms/SampleMapperTest.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/demo/TestForms/StringExtensionTest.Designer.cs b/demo/TestForms/StringExtensionTest.Designer.cs new file mode 100644 index 0000000..02c7708 --- /dev/null +++ b/demo/TestForms/StringExtensionTest.Designer.cs @@ -0,0 +1,125 @@ +namespace demo.TestForms; + +partial class StringExtensionTest +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose (bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent () + { + stringInputLabel = new Label(); + stringInput = new TextBox(); + replaceInput = new TextBox(); + replaceInputLabel = new Label(); + resultLabel = new Label(); + doItButton = new Button(); + SuspendLayout(); + // + // stringInputLabel + // + stringInputLabel.AutoSize = true; + stringInputLabel.Location = new Point(12, 9); + stringInputLabel.Name = "stringInputLabel"; + stringInputLabel.Size = new Size(119, 17); + stringInputLabel.TabIndex = 0; + stringInputLabel.Text = "&Введите строку:"; + // + // stringInput + // + stringInput.Location = new Point(12, 29); + stringInput.Name = "stringInput"; + stringInput.Size = new Size(1005, 26); + stringInput.TabIndex = 1; + // + // replaceInput + // + replaceInput.Location = new Point(12, 89); + replaceInput.Multiline = true; + replaceInput.Name = "replaceInput"; + replaceInput.Size = new Size(1005, 307); + replaceInput.TabIndex = 2; + // + // replaceInputLabel + // + replaceInputLabel.AutoSize = true; + replaceInputLabel.Location = new Point(12, 69); + replaceInputLabel.Name = "replaceInputLabel"; + replaceInputLabel.Size = new Size(235, 17); + replaceInputLabel.TabIndex = 3; + replaceInputLabel.Text = "&Введите массив замен (что=чем):"; + // + // resultLabel + // + resultLabel.Dock = DockStyle.Bottom; + resultLabel.Location = new Point(0, 454); + resultLabel.Name = "resultLabel"; + resultLabel.Padding = new Padding(10); + resultLabel.Size = new Size(1025, 184); + resultLabel.TabIndex = 4; + resultLabel.Text = "&Введите данные и нажмите кнопку «Преобразовать», чтобы увидеть здесь резкльтат..."; + // + // doItButton + // + doItButton.Location = new Point(12, 402); + doItButton.Name = "doItButton"; + doItButton.Size = new Size(1005, 43); + doItButton.TabIndex = 5; + doItButton.Text = "&Преобразовать"; + doItButton.UseVisualStyleBackColor = true; + doItButton.Click += doItButton_Click; + // + // StringExtensionTest + // + AutoScaleDimensions = new SizeF(9F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(1025, 638); + Controls.Add(doItButton); + Controls.Add(resultLabel); + Controls.Add(replaceInputLabel); + Controls.Add(replaceInput); + Controls.Add(stringInput); + Controls.Add(stringInputLabel); + Font = new Font("XO Thames", 12F, FontStyle.Regular, GraphicsUnit.Point, 204); + FormBorderStyle = FormBorderStyle.Fixed3D; + Margin = new Padding(4, 3, 4, 3); + MaximizeBox = false; + MinimizeBox = false; + Name = "StringExtensionTest"; + ShowIcon = false; + ShowInTaskbar = false; + StartPosition = FormStartPosition.CenterScreen; + Text = "Тест расширения класса string"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label stringInputLabel; + private TextBox stringInput; + private TextBox replaceInput; + private Label replaceInputLabel; + private Label resultLabel; + private Button doItButton; +} \ No newline at end of file diff --git a/demo/TestForms/StringExtensionTest.cs b/demo/TestForms/StringExtensionTest.cs new file mode 100644 index 0000000..259d93f --- /dev/null +++ b/demo/TestForms/StringExtensionTest.cs @@ -0,0 +1,47 @@ +using anbs_cp.Classes; +using anbs_cp.Extensions; + +namespace demo.TestForms; +public partial class StringExtensionTest: Form +{ + public StringExtensionTest () + { + InitializeComponent(); + } + + private void doItButton_Click (object sender, EventArgs e) + { + if (stringInput.Text.IsNullOrWhiteSpace()) + { + resultLabel.Text = @"Ошибка! Не заполнено поле ввода строки на замену!"; + + return; + } + + if (replaceInput.Text.IsNullOrWhiteSpace()) + { + resultLabel.Text = @"Ошибка! Не заполнено поле ввода списка замен!"; + + return; + } + + string[] lines = replaceInput.Text.ReplaceLineEndings(";").Split(';'); + + KeyValueOrderedList replaceList = []; + + foreach (string line in lines) + { + string[] splitLine = line.Split('='); + + if (splitLine.Length < 2) + continue; + + string key = splitLine[0]; + string value = splitLine[1]; + + replaceList.Add(new(key, value)); + } + + resultLabel.Text = stringInput.Text.Format(replaceList, StringComparison.CurrentCultureIgnoreCase); + } +} diff --git a/demo/TestForms/StringExtensionTest.resx b/demo/TestForms/StringExtensionTest.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/demo/TestForms/StringExtensionTest.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/demo/demo.csproj b/demo/demo.csproj index d547f4c..a5d1369 100644 --- a/demo/demo.csproj +++ b/demo/demo.csproj @@ -24,9 +24,7 @@ - - Form - + \ No newline at end of file diff --git a/demo2/Program.cs b/demo2/Program.cs new file mode 100644 index 0000000..9670dd0 --- /dev/null +++ b/demo2/Program.cs @@ -0,0 +1,49 @@ +using anbs_cp.Classes; +using anbs_cp.Enums; +using anbs_cp.Extensions; + +// KeyValueOrderedTest +void DoTest1 () +{ + Console.WriteLine("Вы выбрали тест KeyValueOrdered. В список будут по очереди добавляться данные."); + KeyValueOrderedList kv = []; + Console.WriteLine("Добавляю данные: я=>Вася"); + kv.Add(new("я", "Вася")); + Console.WriteLine(kv.Serialize()); + Console.WriteLine("Добавляю данные: он=>Петя"); + kv.Add(new("он", "Петя")); + Console.WriteLine(kv.Serialize()); + Console.WriteLine("Добавляю данные: я=>Саша"); + kv.Add(new("я", "Саша")); + Console.WriteLine(kv.Serialize()); + Console.ReadLine(); +} + +// StringExtensions 1 +void DoTest2 () +{ + Console.WriteLine("Вы выбрали тест StringExtensions 1. Введите предложение:"); + string str = Console.ReadLine() ?? string.Empty; + Console.WriteLine($"None: {str.Transform(ETextTransform.None)}"); + Console.WriteLine($"LowerCase: {str.Transform(ETextTransform.LowerCase)}"); + Console.WriteLine($"UpperCase: {str.Transform(ETextTransform.UpperCase)}"); + Console.WriteLine($"FirstUpper: {str.Transform(ETextTransform.FirstUpper)}"); + Console.ReadLine(); +} + +Console.WriteLine("Выберете тест:"); + +if (!int.TryParse(Console.ReadLine(), out int testNum)) + testNum = 0; + +switch (testNum) +{ + case 0: + break; + case 1: + DoTest1(); + break; + case 2: + DoTest2(); + break; +} \ No newline at end of file diff --git a/demo2/demo2.csproj b/demo2/demo2.csproj new file mode 100644 index 0000000..e4eda35 --- /dev/null +++ b/demo2/demo2.csproj @@ -0,0 +1,16 @@ + + + + Exe + net8.0 + enable + enable + true + true + + + + + + +