Compare commits

..

No commits in common. "master" and "oldrelease" have entirely different histories.

132 changed files with 451 additions and 9159 deletions

View File

@ -1,4 +0,0 @@
[*.cs]
# SYSLIB1045: Преобразовать в "GeneratedRegexAttribute".
dotnet_diagnostic.SYSLIB1045.severity = silent

View File

@ -1,5 +1,7 @@
# Что такое ANB Software Components Pack?
ANB Software Components Pack - набор полезных классов C#, которые расширяют возможности языка. Они могут использоваться в приложенях для ОС Widows и серверов на базе этой ОС.
ANB Software Components Pack - набор полезных классов C#, которые расширяют возможности языка.
Они могут использоваться в приложенях для ОС Widows и серверов на базе этой ОС.
# Лицензия
MIIT

View File

@ -1,340 +0,0 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable MemberCanBeProtected.Global
using anbs_cp.Enums;
using anbs_cp.Interfaces;
namespace anbs_cp.Classes;
/*
История версий
Обновлено 2024.03.28
* Все поля Errors, Warnings и Infos объеденины в одно Messages
* В ActionStateMessage добавлен параметр, определяющий тип: MessageType
Обновлено 2024.03.26
* Все интерфейсы объеденины в один класс ActionStateMessage
* Интерфейс IActionState удалён
Обновлено 2023.12.10
* Заменены классы Action* на соответствующие интерфейсы
* Класс ActionState теперь наследует интерфейс IActionState, позволяющий добавлять состояния (ошибки, предупреждения и информацию)
из разных классов ActionState, т.е. например, данные из ActionState<bool> (кроме значения!) можно перенести в ActionState<int>.
Обновлено 2023.11.1
* Добавлен возвращаемый результат
Обновлено 2023.01.121.1:
* Заменены интерфейсы IAction* на соответствующие классы
*/
/// <summary>
/// Состояние действия
/// </summary>
/// <typeparam name="T">Тип класса</typeparam>
public class ActionState<T>: ISerializable
{
/// <summary>
/// Список информации
/// </summary>
// ReSharper disable once CollectionNeverQueried.Local
internal List<ActionStateMessage> Messages { get; } = [];
/// <summary>
/// Значение
/// </summary>
public T? Value { get; set; }
/// <summary>
/// Метод для выбора всех значений для условия
/// </summary>
// ReSharper disable once StaticMemberInGenericType
public static readonly Func<ActionStateMessage, bool> SelectAll = static _ => true;
#region Методы
#region Очистка
/// <summary>
/// Очищает список ошибок
/// </summary>
public void ClearErrors ()
{
Clear(static message => message.MessageType == EActionStateMessageType.Error);
}
/// <summary>
/// Очищает список предупреждений
/// </summary>
public void ClearWarnings ()
{
Clear(static message => message.MessageType == EActionStateMessageType.Warning);
}
/// <summary>
/// Очищает список информации
/// </summary>
public void ClearInfo ()
{
Clear(static message => message.MessageType == EActionStateMessageType.Information);
}
/// <summary>
/// Очищает список по условию <paramref name="predicate"/>
/// </summary>
/// <param name="predicate">Условие выборки</param>
public void Clear (Func<ActionStateMessage, bool> predicate)
{
// Получаю список элементов
IEnumerable<ActionStateMessage> list = Messages.Where(predicate);
// Для каждого элемента
foreach (ActionStateMessage actionStateMessage in list)
// - запускаю его удаление
Messages.Remove(actionStateMessage);
}
#endregion
#region Добавление
/// <summary>
/// Добавление сообщения
/// </summary>
/// <param name="message">Сообщение</param>
// ReSharper disable once MemberCanBeMadeStatic.Global
// ReSharper disable once FunctionRecursiveOnAllPaths
public void Add (ActionStateMessage message) => Messages.Add(message);
/// <summary>
/// Добавляет список
/// </summary>
/// <param name="messages">Список сообщений</param>
public void AddRange (IEnumerable<ActionStateMessage> messages) => Messages.AddRange(messages);
#endregion
#region Добавление ошибки
/// <summary>
/// Добавление ошибки
/// </summary>
/// <param name="critical">Является ли ошибка критической</param>
public void AddError (bool critical = true) => Add(new(EActionStateMessageType.Error, critical));
/// <summary>
/// Добавление ошибки
/// </summary>
/// <param name="message">Сообщение об ошибке</param>
/// <param name="critical">Является ли ошибка критической</param>
public void AddError (string message, bool critical = true) =>
Add(new(EActionStateMessageType.Error, critical, message: message));
/// <summary>
/// Добавление ошибки
/// </summary>
/// <param name="errorObject">Объект ошибки</param>
/// <param name="message">Сообщение об ошибке</param>
/// /// <param name="critical">Является ли ошибка критической</param>
public void AddError (string errorObject, string message, bool critical = true) =>
Add(new(EActionStateMessageType.Error, critical, errorObject, message));
#endregion
#region Добавление предупреждения
/// <summary>
/// Добавление предупреждение
/// </summary>
/// <param name="message">Текст предупреждения</param>
/// <param name="warningObject">Объект предупреждения</param>
public void AddWarning (string message, string warningObject = "") =>
Add(new(EActionStateMessageType.Warning, message: message, obj: warningObject));
#endregion
#region Добавление информации
/// <summary>
/// Добавление информации
/// </summary>
/// <param name="message">Текст информации</param>
/// <param name="infoObject">Объект информации</param>
public void AddInfo (string message, string infoObject = "") => Add(new(message: message, obj: infoObject));
#endregion
#region Печать
/// <summary>
/// Печать сообщений
/// </summary>
/// <param name="area">Область печати</param>
/// <param name="formatList">Оформление всей области</param>
/// <param name="formatItem">Оформление элемента</param>
/// <returns>Текстовое представление выбранных списокв</returns>
/// <exception cref="ArgumentOutOfRangeException">Ошибка при неизвестной области</exception>
public string PrintMessage (EActionStatePrintArea area, string formatList, string formatItem)
{
// Создаю список
List<ActionStateMessage> list = [];
// Выбираю списки по областям
switch (area)
{
case EActionStatePrintArea.All:
list.AddRange(Messages);
break;
case EActionStatePrintArea.ErrorsAndWarnings:
list.AddRange(Messages.Where(static message =>
message.MessageType is EActionStateMessageType.Error or EActionStateMessageType.Warning));
break;
case EActionStatePrintArea.ErrorsOnly:
list.AddRange(Messages.Where(static message => message.MessageType == EActionStateMessageType.Error));
break;
case EActionStatePrintArea.WarningsOnly:
list.AddRange(Messages.Where(static message => message.MessageType == EActionStateMessageType.Warning));
break;
case EActionStatePrintArea.InfosOnly:
list.AddRange(Messages.Where(static message =>
message.MessageType == EActionStateMessageType.Information));
break;
default:
throw new ArgumentOutOfRangeException(nameof(area), area, null);
}
// Создаю элементы
string elements =
list.Aggregate(string.Empty, (current, item) => current + item.PrintMessage(formatItem));
return string.Format(formatList, elements);
}
#endregion
#region Проверка на наличие
/// <summary>
/// Проверяет, есть ли ошибки
/// </summary>
/// <param name="ignoreNonCritical">Игнорировать не критические</param>
/// <returns>Наличие ошибок</returns>
public bool HasErrors (bool ignoreNonCritical = false) => Messages.Any(message =>
message.MessageType == EActionStateMessageType.Error && (!ignoreNonCritical || !message.IsCritical));
/// <summary>
/// Проверяет, есть ли предупреждения
/// </summary>
/// <param name="ignoreInformWarning">Игнорировать информационные предупреждения</param>
/// <returns>Наличие предупреждений</returns>
public bool HasWarnings (bool ignoreInformWarning = false) => Messages.Any(message =>
message.MessageType == EActionStateMessageType.Warning && (!ignoreInformWarning || !message.IsCritical));
/// <summary>
/// Проверяет, есть ли сообщения
/// </summary>
/// <param name="ignoreStatus">Игнорировать статусные сообщения</param>
/// <returns>Наличие сообщений</returns>
public bool HasInfo (bool ignoreStatus) => Messages.Any(message =>
message.MessageType == EActionStateMessageType.Information && (!ignoreStatus || !message.IsCritical));
/// <summary>
/// Успешно ли завершилось
/// </summary>
public bool IsSuccess (bool ignoreNonCriticalErrors = false) =>
!HasErrors(ignoreNonCriticalErrors) && !HasWarnings(true);
#endregion
#region Количество сообщений
/// <summary>
/// Количество сообщений, удовлеьворяющих условию <paramref name="predicate"/>
/// </summary>
/// <param name="predicate">Условие выборки</param>
/// <returns>Число сообщений</returns>
public int Count (Func<ActionStateMessage, bool> predicate) => Messages.Count(predicate);
/// <summary>
/// Количество ошибок
/// </summary>
/// <param name="ignoreNonCritical">Игнорировать не критические</param>
/// <returns>Количество ошибок</returns>
public int ErrorsCount (bool ignoreNonCritical = false) => Count(message =>
message.MessageType == EActionStateMessageType.Error && (!ignoreNonCritical || !message.IsCritical));
/// <summary>
/// Количество предупреждений
/// </summary>
/// <param name="ignoreInformWarning">Игнорировать информационные предупреждения</param>
/// <returns>Количество предупреждений</returns>
public int WarningsCount (bool ignoreInformWarning = false) => Count(message =>
message.MessageType == EActionStateMessageType.Warning && (!ignoreInformWarning || !message.IsCritical));
/// <summary>
/// Количество информационных сообщений
/// </summary>
/// <param name="ignoreStatus">Игнорировать статусные сообщения</param>
/// <returns>Количество информационных сообщений</returns>
public int InfoCount (bool ignoreStatus) => Count(message =>
message.MessageType == EActionStateMessageType.Information && (!ignoreStatus || !message.IsCritical));
#endregion
#region Добавление другого состояния
/// <summary>
/// Добавляет другое состояние (например, результат другого действия, который возвращает <see cref="ActionState"/>).
/// </summary>
/// <typeparam name="TO">Тип параметра</typeparam>
/// <param name="state">Запись состояния</param>
public void AddState<TO> (ActionState<TO> state) => AddRange(state.Messages);
#endregion
#endregion
#region Реализация интерфейса ISerializable
/// <inheritdoc />
public string Serialize ()
{
// Создаю модель
ActionStateSerializable serializableModel = new();
// Для каждого сообщения
foreach (ActionStateMessage message in Messages)
// - добавляю в модель
serializableModel.Messages.Add(message.Serialize());
// Создаю модель значения
ActionStateSerializableValue value = new();
// Получаю данные
value.GetValue(Value);
// Добавляю в модель
serializableModel.Value = value.Serialize();
// Возвращаю сериализованную модель
return new NewtonsoftJsonSerializer().Serialize(serializableModel);
}
/// <inheritdoc />
public void Deserialize (string json)
{
// Удаляю лишние символы
json = json.Trim("\"".ToCharArray());
// Десериализую строку
ActionStateSerializable itemSerializable =
new NewtonsoftJsonSerializer().Deserialize<ActionStateSerializable>(json) ?? new();
// Создаю модель значения
ActionStateSerializableValue value = new();
// Очищаю списки
Clear(SelectAll);
// Для каждого сообщения
foreach (string messageString in itemSerializable.Messages)
{
// - создаю сообщение
ActionStateMessage message = new();
// - десериализую в него данные из модели
message.Deserialize(messageString);
// - добавляю в список
Add(message);
}
// Десериализую данные значения из модели
value.Deserialize(itemSerializable.Value);
// Получаю значение
Value = value.SetValue<T>();
}
#endregion
}

View File

@ -1,115 +0,0 @@
// ReSharper disable MemberCanBeInternal
// ReSharper disable MemberCanBePrivate.Global
using anbs_cp.Enums;
using anbs_cp.Interfaces;
namespace anbs_cp.Classes;
/// <summary>
/// Класс сообщения состояния
/// </summary>
public sealed class ActionStateMessage (
EActionStateMessageType type = EActionStateMessageType.Information,
bool isCritical = false,
string obj = "",
string message = ""): ISerializable
{
#region Свойства
/// <summary>
/// Тип сообщения
/// </summary>
public EActionStateMessageType MessageType { get; set; } = type;
/// <summary>
/// Критичность сообщения
/// </summary>
public bool IsCritical { get; set; } = isCritical;
/// <summary>
/// Объект сообщения
/// </summary>
public string Object { get; set; } = obj;
/// <summary>
/// Текст сообщения
/// </summary>
public string Message { get; set; } = message;
#endregion
#region Методы
/// <summary>
/// Вывод сообщения
/// </summary>
/// <param name="format">Строка-форматирование (например, «[{0}] - {1}»)</param>
/// <returns>Отформатированную строка</returns>
public string PrintMessage (string format) => string.Format(format, Object, Message);
/// <summary>
/// Устанавливает объект
/// </summary>
/// <param name="obj">Объект</param>
/// <typeparam name="T">Тип объекта</typeparam>
public void SetObject<T> (T obj)
{
// Если объект реализует интерфейс ISerializable
if (obj is ISerializable serializable)
{
// - то сериализуем его методами интерфейса
Object = serializable.Serialize();
// - и прерываем
return;
}
// Сериализуем объект с помощью NewtonsoftJson
Object = new NewtonsoftJsonSerializer().Serialize(obj);
}
/// <summary>
/// Получает объект
/// </summary>
/// <typeparam name="T">Класс объекта</typeparam>
/// <returns>Объект или null</returns>
public T? GetObject<T> () => new NewtonsoftJsonSerializer().Deserialize<T>(Object);
/// <summary>
/// Получает объект
/// </summary>
/// <typeparam name="T">Класс объекта, реализующий интерфейс ISerializable</typeparam>
/// <returns>Объект</returns>
public T GetSerializedObject<T> () where T : ISerializable, new()
{
// Создаём результирующую модель
T model = new();
// Десериализуем её методами интерфейса ISerializable
model.Deserialize(Object);
// Возвращаем модель
return model;
}
#endregion
#region Реализация интерфейса ISerializable
/// <inheritdoc />
public string Serialize () => new NewtonsoftJsonSerializer().Serialize(this);
/// <inheritdoc />
public void Deserialize (string json)
{
// Десериализую строку
ActionStateMessage item = new NewtonsoftJsonSerializer().Deserialize<ActionStateMessage>(json) ?? new();
// Передаю параметры
MessageType = item.MessageType;
IsCritical = item.IsCritical;
Object = item.Object;
Message = item.Message;
}
#endregion
}

View File

@ -1,18 +0,0 @@
// ReSharper disable CollectionNeverUpdated.Global
namespace anbs_cp.Classes;
/// <summary>
/// Сериализованная модель класса, хранящего в себе состояния действия
/// </summary>
public class ActionStateSerializable
{
/// <summary>
/// Список всех сообщений
/// </summary>
public List<string> Messages { get; } = [];
/// <summary>
/// Значение
/// </summary>
public string Value { get; set; } = string.Empty;
}

View File

@ -1,96 +0,0 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable MemberCanBeInternal
using anbs_cp.Interfaces;
namespace anbs_cp.Classes;
/// <summary>
/// Сериализованная модель значения класса, хранящего в себе состояния действия
/// </summary>
public sealed class ActionStateSerializableValue: ISerializable
{
/// <summary>
/// Значение - null?
/// </summary>
public bool IsNull { get; set; }
/// <summary>
/// Сериализуемое значение
/// </summary>
public string Serialized { get; set; } = string.Empty;
/// <summary>
/// Получает значение из <paramref name="value"/>
/// </summary>
/// <param name="value">Значение</param>
/// <typeparam name="T">Тип значения</typeparam>
internal void GetValue<T> (T? value)
{
// Значение - null?
IsNull = value is null;
// Если не null
// - сериализую
Serialized = value is not null ? new SysTextSerializer().Serialize(value) : string.Empty;
}
/// <summary>
/// Устанавливает значение
/// </summary>
/// <typeparam name="T">Класс</typeparam>
/// <returns>Значение</returns>
internal T? SetValue<T> () => IsNull ? default : new SysTextSerializer().Deserialize<T>(Serialized);
/// <summary>
/// Получает значение из <paramref name="value"/>
/// </summary>
/// <param name="value">Значение</param>
/// <typeparam name="T">Тип значения</typeparam>
internal void GetSerializedValue<T> (T? value) where T : ISerializable, new()
{
// Значение - null?
IsNull = value is null;
// Если не null
// - сериализую
Serialized = value is not null ? value.Serialize() : string.Empty;
}
/// <summary>
/// Устанавливает значение
/// </summary>
/// <typeparam name="T">Класс</typeparam>
/// <returns>Значение</returns>
internal T? SetSerializedValue<T> () where T : ISerializable, new()
{
// Если null
if (IsNull)
// - то возвращаем null
return default;
// Создаю модель
T model = new ();
// Десериализую модель
model.Deserialize(Serialized);
// Возвращаю модель
return model;
}
#region Реализация интерфейса ISerializable
/// <inheritdoc />
public string Serialize () => new SysTextSerializer().Serialize(this);
/// <inheritdoc />
public void Deserialize (string json)
{
// Десериализую строку
ActionStateSerializableValue item = new SysTextSerializer().Deserialize<ActionStateSerializableValue>(json) ?? new();
// Передаю параметры
IsNull = item.IsNull;
Serialized = item.Serialized;
}
#endregion
}

View File

@ -1,86 +0,0 @@
using anbs_cp.Exceptions;
using anbs_cp.Interfaces;
namespace anbs_cp.Classes;
/// <summary>
/// Состояние действия
///
/// Обновлено 2024.03.26
/// * Добавлен класс ActionState для классов, поддерживаемых интерфейс I
/// </summary>
public sealed class ActionStateSerialized<T>: ActionState<T> where T : ISerializable, new()
{
/// <summary>
/// Добавляет другое состояние (например, результат другого действия, который возвращает <see cref="ActionState"/>).
/// </summary>
/// <param name="state">Запись состояния</param>
public void AddState (ActionStateSerialized<T> state)
{
base.AddState(state);
}
#region Переопределение реализации интерфейса ISerializable
/// <summary>
/// Сериализовать элемент в формат json
/// </summary>
/// <returns>Строка в формате json</returns>
/// <exception cref="SerializeException">Ошибка при сериализации</exception>
public new string Serialize ()
{
// Создаю модель
ActionStateSerializable serializableModel = new();
// Для каждого сообщения
foreach (ActionStateMessage message in Messages)
// - добавляю в модель
serializableModel.Messages.Add(message.Serialize());
// Создаю модель значения
ActionStateSerializableValue value = new();
// Получаю данные
value.GetSerializedValue(Value);
// Добавляю в модель
serializableModel.Value = value.Serialize();
// Возвращаю сериализованную модель
return new SysTextSerializer().Serialize(serializableModel);
}
/// <summary>
/// Восстановить элемент из формата json
/// </summary>
/// <param name="json">Строка в формате json</param>
/// <exception cref="SerializeException">Ошибка при десериализации</exception>
public new void Deserialize (string json)
{
// Десериализую строку
ActionStateSerializable itemSerializable = new SysTextSerializer().Deserialize<ActionStateSerializable>(json) ?? new();
// Создаю модель значения
ActionStateSerializableValue value = new();
// Очищаю списки
Clear(SelectAll);
// Для каждого сообщения
foreach (string messageString in itemSerializable.Messages)
{
// - создаю сообщение
ActionStateMessage message = new();
// - десериализую в него данные из модели
message.Deserialize(messageString);
// - добавляю в список
Add(message);
}
// Десериализую данные значения из модели
value.Deserialize(itemSerializable.Value);
// Получаю значение
Value = value.SetSerializedValue<T>();
}
#endregion
}

View File

@ -1,19 +0,0 @@
namespace anbs_cp.Classes;
/// <summary>
/// Состояние действия
///
/// Обновлено 2023.11.1
/// * Добавлен класс ActionState без возвращаемого значения
/// </summary>
public sealed class ActionState: ActionState<string>
{
/// <summary>
/// Добавляет другое состояние (например, результат другого действия, который возвращает <see cref="ActionState"/>).
/// </summary>
/// <param name="state">Запись состояния</param>
public void AddState (ActionState state)
{
base.AddState(state);
}
}

View File

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

View File

@ -1,13 +0,0 @@
namespace anbs_cp.Classes;
/// <summary>
/// Конвертер количества элементов
/// </summary>
public sealed class CountConverter (IEnumerable<string> valueNames, byte decimalPlace = 0): ValueConverter(
valueNames, 1000, decimalPlace)
{
/// <summary>
/// Имена размеров файлов по умолчанию
/// </summary>
public static readonly string[] DefaultNames = { "", "тыс.", "млн." };
}

View File

@ -1,50 +0,0 @@
using anbs_cp.Interfaces;
namespace anbs_cp.Classes;
/// <summary>
/// Форматирует число элементов в понятную строку
/// </summary>
public sealed class CountFormatter : IValueFormatter
{
#region ойства класса
/// <summary>
/// Имена чисел (тысяч, миллионов, миллиардов и т.п.)
/// </summary>
public string[] CountNames { get; set; } = { "", "тыс.", "млн.", "млрд." };
/// <summary>
/// Знаков после запятой
/// </summary>
public byte DecimalPlaces { get; set; } = 1;
/// <summary>
/// Делители чисел
/// </summary>
public long[] Delimeters { get; set; } = { 1000, 1000000, 1000000000 };
#endregion
#region Реализация интерфейса
/// <summary>
/// Реализация интерфейса
/// </summary>
public string[] ValueNames
{
get => CountNames;
set => CountNames = value;
}
/// <summary>
/// Реализация интерфейса
/// </summary>
public long[] MaxSizes
{
get => Delimeters;
set => Delimeters = value;
}
#endregion
}

View File

@ -1,37 +0,0 @@
namespace anbs_cp.Classes.Encrypt;
/// <summary>
/// Статическая обертка для класса шифровки строк StringEncryptor
/// </summary>
public static class StringEncrypt
{
/// <summary>
/// Метод для шифрования строки <paramref name="text"/>
/// </summary>
/// <param name="text">Строка, которая должна быть зашифрована</param>
/// <param name="key">Ключ</param>
/// <returns>Этот статический метод возвращает зашифрованную строку <paramref name="text"/></returns>
public static string Encrypt (string text, string key) => new StringEncryptor().Encrypt(text, key);
/// <summary>
/// Метод для дешифрования строки <paramref name="text"/>
/// </summary>
/// <param name="text">Строка, которая должна быть дешифрована</param>
/// <param name="key">Ключ</param>
/// <returns>Этот статический метод возвращает дешифрованную строку <paramref name="text"/></returns>
public static string Decrypt (string text, string key) => new StringEncryptor().Decrypt(text, key);
/// <summary>
/// Декодирует зашифрованную строку в HTML-пригодный формат
/// </summary>
/// <param name="text">Зашифрованная строка</param>
/// <returns>Этот статический метод возвращает дешифрованную строку <paramref name="text"/></returns>
public static string Base64UrlEncode (string text) => new StringEncryptor().Base64UrlEncode(text);
/// <summary>
/// Раскодирует из декодированной строки в HTML-пригодный формат
/// </summary>
/// <param name="text">Декодированная строка</param>
/// <returns>Этот статический метод возвращает шифрованную строку <paramref name="text"/></returns>
public static string Base64UrlDecode (string text) => new StringEncryptor().Base64UrlDecode(text);
}

View File

@ -1,157 +0,0 @@
using System.Security.Cryptography;
using System.Text;
using anbs_cp.Interfaces;
namespace anbs_cp.Classes.Encrypt;
/// <summary>
/// Класс для шифровки строк
/// </summary>
public sealed class StringEncryptor: IEncryptor
{
/// <summary>
/// Получение ключа из строки
/// </summary>
/// <param name="s">Ключ-строка</param>
/// <param name="salt">Хэш-ключ</param>
/// <returns>Ключ</returns>
private static byte[] KeyFromString (string s, byte[] salt)
{
// Создаю хэшер
using Rfc2898DeriveBytes hasher = new(s, salt, 1000, HashAlgorithmName.SHA256);
// Получаю ключ
return hasher.GetBytes(32);
}
/// <summary>
/// Метод для шифрования строки <paramref name="value"/>
/// </summary>
/// <param name="value">Строка, которая должна быть зашифрована</param>
/// <param name="salt">Ключ</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>Этот метод возвращает зашифрованную строку <paramref name="value"/></returns>
/// <exception cref="FormatException">Ошибка неверного формата</exception>
public string Encrypt (string value, string salt, string valueIfFail = "")
{
try
{
// Создаю криптограф
using Aes aes = Aes.Create();
// Получаю ключ
aes.Key = KeyFromString(salt, aes.IV);
// Открываю поток
using MemoryStream ms = new();
// Пишу данные в поток
ms.Write(aes.IV);
// Создаю шифрованный поток
using (CryptoStream cs = new(ms, aes.CreateEncryptor(), CryptoStreamMode.Write, true))
// Пишу данные в него
cs.Write(Encoding.UTF8.GetBytes(value));
// Возвращаю зашифрованный текст
return Convert.ToBase64String(ms.ToArray());
}
catch (FormatException)
{
return valueIfFail;
}
}
/// <summary>
/// Метод для дешифрования строки <paramref name="encryptedValue"/>
/// </summary>
/// <param name="encryptedValue">Строка, которая должна быть дешифрована</param>
/// <param name="salt">Ключ</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>Этот метод возвращает дешифрованную строку <paramref name="encryptedValue"/></returns>
/// <exception cref="FormatException">Ошибка неверного формата</exception>
public string Decrypt (string encryptedValue, string salt, string valueIfFail = "")
{
try
{
// Открываю поток в памяти
using MemoryStream ms = new(Convert.FromBase64String(encryptedValue));
// Задаю ключ
byte[] iv = new byte[16];
// Читаю его
_ = ms.Read(iv);
// Создаю криптограф
using Aes aes = Aes.Create();
// Получаю ключ
aes.Key = KeyFromString(salt, iv);
// присваиваю ключ
aes.IV = iv;
// Создаю поток дешифратора
using CryptoStream cs = new(ms, aes.CreateDecryptor(), CryptoStreamMode.Read, true);
// Задаю поток итогового текста
using MemoryStream output = new();
// Копирую данные в выходной поток
cs.CopyTo(output);
// Вывожу расшифрованный текст
return Encoding.UTF8.GetString(output.ToArray());
}
catch (FormatException)
{
return valueIfFail;
}
}
/// <summary>
/// Декодирует зашифрованную строку в HTML-пригодный формат
/// </summary>
/// <param name="text">Зашифрованная строка</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>Этот метод возвращает дешифрованную строку <paramref name="text"/></returns>
/// <exception cref="FormatException">Ошибка неверного формата</exception>
public string Base64UrlEncode(string text, string valueIfFail = "") =>
text.TrimEnd('=').Replace('+', '-').Replace('/', '_');
/// <summary>
/// Раскодирует из декодированной строки в HTML-пригодный формат
/// </summary>
/// <param name="text">Декодированная строка</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>Этот метод возвращает шифрованную строку <paramref name="text"/></returns>
/// <exception cref="FormatException">Ошибка неверного формата</exception>
public string Base64UrlDecode (string text, string valueIfFail = "")
{
try
{
// Первоначальная замена
string result = text.Replace('_', '/').Replace('-', '+');
// Заменяю значения
switch (result.Length % 4)
{
case 2:
result += "==";
break;
case 3:
result += "=";
break;
}
// Возвращаю результат
return result;
}
catch (FormatException)
{
return valueIfFail;
}
}
}

View File

@ -1,37 +0,0 @@
namespace anbs_cp.Classes.Exceptions;
/// <summary>
/// Класс-исключение для переименования папок/файлов
/// </summary>
public sealed class RenameException : Exception
{
/// <summary>
/// Имя файла/папки
/// </summary>
public string FileName { get; }
/// <summary>
/// Описание ошибки
/// </summary>
public string? ErrorMessage { get; }
/// <summary>
/// Конструктор
/// </summary>
/// <param name="fileName">Имя файла/папки</param>
/// <param name="errorMessage">Описание ошибки</param>
public RenameException(string fileName, string? errorMessage) : base(GetMessage(fileName, errorMessage ?? string.Empty))
{
FileName = fileName;
ErrorMessage = errorMessage;
}
/// <summary>
/// Получение текстового представление ошибки
/// </summary>
/// <param name="fileName">Имя файла/папки</param>
/// <param name="errorMessage">Описание ошибки</param>
/// <returns>Текстовое представление ошибки</returns>
private static string GetMessage(string fileName, string errorMessage) =>
$"При переименовании файла/папки {fileName} возникла следующая ошибка: {errorMessage}";
}

View File

@ -1,58 +0,0 @@
using System.Security.Cryptography;
using System.Text;
namespace anbs_cp.Classes;
/// <summary>
/// Класс для работы с хэшем файла
/// </summary>
public sealed class FileHash
{
/// <summary>
/// Получение md5-хэша файла.
/// Взято с https://stackoverflow.com/a/24031467/16469671
/// </summary>
/// <param name="fileName">Имя файла</param>
/// <returns>Массив хэша</returns>
public FileHash (string fileName)
{
using MD5 md5 = MD5.Create();
using FileStream stream = File.OpenRead(fileName);
Hash = md5.ComputeHash(stream);
}
/// <summary>
/// Простой конструктор
/// </summary>
public FileHash () => Hash = [];
/// <summary>
/// Хэш файла
/// </summary>
public byte[] Hash { get; private set; }
/// <summary>
/// Вывод в строку
/// </summary>
/// <returns>Строка хэша файла</returns>
public override string ToString () => BitConverter.ToString(Hash).Replace("-", "").ToLowerInvariant();
/// <summary>
/// Конвертирует строку в хэш
/// </summary>
/// <param name="value">Строка</param>
public void FromString (string value)
{
UTF8Encoding utf8 = new();
Hash = utf8.GetBytes(value);
}
/// <summary>
/// Сравнивает текущий хэш с хэшем <paramref name="otherHash"/> и выдаёт <see cref="bool.TrueString"/>, если совпадают,
/// и <see cref="bool.FalseString"/>, если не совпадают.
/// </summary>
/// <param name="otherHash">Другой хэш</param>
/// <returns><see cref="bool.TrueString"/>, если совпадают, и <see cref="bool.FalseString"/>, если не совпадают</returns>
public bool IsEqual (FileHash otherHash) =>
string.Equals(ToString(), otherHash.ToString(), StringComparison.OrdinalIgnoreCase);
}

View File

@ -1,15 +0,0 @@
namespace anbs_cp.Classes;
/// <summary>
/// Конвертер размеров файлов
/// </summary>
/// <param name="valueNames">Массив имён размерностей</param>
/// <param name="decimalPlace">Знаков после запятой (0, 1, 2)</param>
public sealed class FileSizeConverter (IEnumerable<string> valueNames, byte decimalPlace = 2): ValueConverter(
valueNames, 1024, decimalPlace)
{
/// <summary>
/// Имена размеров файлов по умолчанию
/// </summary>
public static readonly string[] DefaultNames = { "байт", "Кб", "Мб", "Гб", "Тб" };
}

View File

@ -1,71 +0,0 @@
using anbs_cp.Interfaces;
namespace anbs_cp.Classes;
/// <summary>
/// Форматирует размер файла/папки в понятную строку
/// </summary>
public class FileSizeFormatter : IValueFormatter
{
#region ойства класса
/// <summary>
/// Имена размеров (байт, килобайт, мегабайт, гигабайт и террабайт)
/// </summary>
public string[] SizeNames { get; set; } = { "Байт", "Кб", "Мб", "Гб", "Тб" };
/// <summary>
/// Знаков после запятой
/// </summary>
public byte DecimalPlaces { get; set; } = 2;
/// <summary>
/// Максимально байт (далее идут Кбайты)
/// </summary>
public long ByteMax { get; set; } = 1024;
/// <summary>
/// Максимально Кбайт (далее идут Мбайты)
/// </summary>
public long KByteMax { get; set; } = 1048576;
/// <summary>
/// Максимально Мбайт (далее идут Гбайты)
/// </summary>
public long MByteMax { get; set; } = 1073741824;
/// <summary>
/// Максимально Гбайт (далее идут Тбайты)
/// </summary>
public long GByteMax { get; set; } = 1099511627776;
#endregion
#region Реализация интерфейса
/// <summary>
/// Реализация интерфейса
/// </summary>
public string[] ValueNames
{
get => SizeNames;
set => SizeNames = value;
}
/// <summary>
/// Реализация интерфейса
/// </summary>
public long[] MaxSizes
{
get => new[] { ByteMax, KByteMax, MByteMax, GByteMax };
set
{
ByteMax = value[0];
KByteMax = value[1];
MByteMax = value[2];
GByteMax = value[3];
}
}
#endregion
}

View File

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

View File

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

View File

@ -1,147 +0,0 @@
using anbs_cp.Classes.Exceptions;
using anbs_cp.Enums;
namespace anbs_cp.Classes;
/// <summary>
/// Класс, добавляющий реализацию некоторых методов Delphi, которые упрощают работу в C#.
/// </summary>
public static class LikeDelphi
{
/// <summary>
/// Аналог функции IncludeTrailingBackslash
/// версия 2.1 (20240403) - исправлена ошибка;
/// версия 2.0 (20231213) - ОС-независимая реализация.
/// </summary>
/// <param name="path">Путь, к которому нужно добавить slash</param>
/// <returns>Путь со slash в конце</returns>
public static string IncludeTrailingBackslash (string path)
{
// Если path не заканчивается slash-ем
if (!path.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
// - то добавляем slash
path += Path.DirectorySeparatorChar;
// Выводим результат
return path;
}
/// <summary>
/// Парсер строки в множество строк
/// </summary>
/// <param name="str">Строка, которую нужно разбить</param>
/// <param name="delimiter">Символ-делитель строки</param>
/// <returns>Массив строк</returns>
public static List<string> ParseString (string str, char delimiter) => [.. str.Split(delimiter)];
/// <summary>
/// Переименовываю файл
/// </summary>
/// <param name="oldName">Старое имя файла (с полным путём)</param>
/// <param name="newName">Новое имя файла (с полным путём)</param>
/// <param name="ifExist">Что делать, если существует</param>
/// <exception cref="RenameException">Если <paramref name="ifExist" /> имеет значение <value>RaiseException</value>, то генерируется ошибка переименования файла</exception>
public static void RenameFile (string oldName, string newName,
EOnExistAction ifExist = EOnExistAction.RaiseException)
{
//Если целевой файл существует
if (File.Exists(newName))
switch (ifExist)
{
//Возбуждать исключение
case EOnExistAction.RaiseException:
throw new RenameException(newName, "Файл уже существует!");
//Прерываю
case EOnExistAction.Abort:
return;
//Игнорирую и перезаписываю файл
case EOnExistAction.Ignore:
break;
//Только для папок (для файлов равносилен RaiseException)
case EOnExistAction.RaiseExceptionIfNotEmpty:
throw new RenameException(newName, "Папка уже существует!");
//Только для папок (для файлов равносилен Abort)
case EOnExistAction.AbortIfNotEmpty:
return;
//по умолчанию - RaiseException
default:
throw new RenameException(newName, "Файл уже существует!");
}
//Перемещаю файл
File.Move(oldName, newName, true);
//Если начальный файл существует
if (File.Exists(oldName))
//- удаляю его
File.Delete(oldName);
}
/// <summary>
/// Удаление папки
/// </summary>
/// <param name="dir">Папка</param>
public static void RemoveDir (string dir) => Directory.Delete(dir, true);
/// <summary>
/// Проверяет папку на пустоту
/// Оригинальный ответ от OwenGlendower (https://www.cyberforum.ru/windows-forms/thread1995240.html)
/// </summary>
/// <param name="dir">Проверяемая папка</param>
/// <returns>Пуста (<value>true</value>) или не пуста (<value>false</value>) папка <see cref="dir"/></returns>
public static bool IsDirEmpty (string dir) => !Directory.EnumerateFiles(dir, "*.*", SearchOption.AllDirectories).Any();
/// <summary>
/// Переименовывает папку
/// </summary>
/// <param name="oldName">Старое имя папки (с полным путём)</param>
/// <param name="newName">Новое имя папки (с полным путём)</param>
/// <param name="ifExist">Что делать, если существует</param>
/// <exception cref="RenameException">Если <paramref name="ifExist" /> имеет значение <value>RaiseException</value>, то генерируется ошибка переименования папки</exception>
public static void RenameDir (string oldName, string newName,
EOnExistAction ifExist = EOnExistAction.RaiseException)
{
//Если целевая папка существует
if (Directory.Exists(newName))
{
switch (ifExist)
{
//Возбуждать исключение
case EOnExistAction.RaiseException:
throw new RenameException(newName, "Папка уже существует!");
//Прерывать
case EOnExistAction.Abort:
return;
//Игнорировать и перезаписывать папку
case EOnExistAction.Ignore:
break;
//Возбуждать исключение, если не пустая
case EOnExistAction.RaiseExceptionIfNotEmpty:
if (!IsDirEmpty(newName))
throw new RenameException(newName, "Папка уже существует и не пуста!");
break;
//Прерывать, если не пустая
case EOnExistAction.AbortIfNotEmpty:
if (!IsDirEmpty(newName))
return;
break;
//по умолчанию - RaiseException
default:
throw new RenameException(newName, "Папка уже существует!");
}
//Удаляю целевую папку
RemoveDir(newName);
}
//Перемещаю папку
Directory.Move(oldName, newName);
//Если начальная папка существует
if (Directory.Exists(oldName))
//- удаляю его
RemoveDir(oldName);
}
}

View File

@ -1,16 +0,0 @@
using anbs_cp.Interfaces;
using Newtonsoft.Json;
namespace anbs_cp.Classes;
/// <inheritdoc />
public class NewtonsoftJsonSerializer: ISerializer
{
/// <inheritdoc />
public string Serialize<T> (T data) => JsonConvert.SerializeObject(data);
/// <inheritdoc />
public T? Deserialize<T>(string json) => JsonConvert.DeserializeObject<T>(json,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
}

View File

@ -1,50 +0,0 @@
namespace anbs_cp.Classes;
/// <summary>
/// Параметры пароля
/// </summary>
public sealed class PasswordOptions
{
/// <summary>
/// Конструктор
/// </summary>
public PasswordOptions ()
{
RequiredLength = 8;
RequireLowercase = true;
RequireUppercase = true;
RequireDigit = true;
RequireNonAlphanumeric = false;
RequiredUniqueChars = 6;
}
/// <summary>
/// Требуемая длина пароля
/// </summary>
public byte RequiredLength { get; set; }
/// <summary>
/// Требовать строчные буквы в пароле
/// </summary>
public bool RequireLowercase { get; set; }
/// <summary>
/// Требовать прописные буквы в пароле
/// </summary>
public bool RequireUppercase { get; set; }
/// <summary>
/// Требовать цифры в пароле
/// </summary>
public bool RequireDigit { get; set; }
/// <summary>
/// Требовать символы
/// </summary>
public bool RequireNonAlphanumeric { get; set; }
/// <summary>
/// Уникальных символов
/// </summary>
public byte RequiredUniqueChars { get; set; }
}

View File

@ -1,133 +0,0 @@
using System.Reflection;
namespace anbs_cp.Classes;
/// <summary>
/// Класс перевода одинаковых свойств из класса TF в класс T.
/// Оригинальные автор(-ы): keenthinker и Avtandil Kavrelishvili.
/// Улучшения: А. Н. Бабаев
/// URL: https://stackoverflow.com/questions/20410234/how-to-automatically-map-the-values-between-instances-of-two-different-classes-i
/// </summary>
public static class SimpleMapper
{
/// <summary>
/// Перевод одинаковых свойств из класса F в класс TT.
/// </summary>
/// <param name="from">Экземпляр класса F</param>
/// <param name="to">Ссылка на экземпляр класса T</param>
/// <param name="mode">Тип сопоставления</param>
/// <param name="list">Список параметров для сопоставления</param>
/// <typeparam name="TF">Класс-родитель</typeparam>
/// <typeparam name="T">Класс-приемник</typeparam>
public static void MapEx<TF, T>(TF from, ref T to, MapMode mode, List<string> list)
{
//Копирую поля
Type typeOfA = typeof(TF);
Type typeOfB = typeof(T);
foreach (FieldInfo fieldOfA in typeOfA.GetFields())
{
//Проверяем выполнение условия и прерываем, если не выполняется
if (!CheckCondition<TF>(fieldOfA.Name, fieldOfA.GetValue(from), mode, list))
continue;
//Получаем FieldInfo для b по имени поля a
FieldInfo? fieldOfB = typeOfB.GetField(fieldOfA.Name);
//Присваиваю поля типа B значение поля типа A
fieldOfB?.SetValue(to, fieldOfA.GetValue(from));
}
//Копирую свойства
foreach (PropertyInfo propertyOfA in typeOfA.GetProperties())
{
//Проверяем выполнение условия и прерываем, если не выполняется
if (!CheckCondition<TF>(propertyOfA.Name, propertyOfA.GetValue(from), mode, list))
continue;
//Получаем PropertyInfo для b по имени свойства a
PropertyInfo? propertyOfB = typeOfB.GetProperty(propertyOfA.Name);
//Присваиваю свойству типа B значение свойства типа A
propertyOfB?.SetValue(to, propertyOfA.GetValue(from));
}
}
/// <summary>
/// Перевод одинаковых свойств из класса F в класс TT (режим "сопоставление всех параметров").
/// </summary>
/// <param name="from">Параметр класса F</param>
/// <typeparam name="TF">Класс-родитель</typeparam>
/// <typeparam name="T">Класс-приемник</typeparam>
/// <returns>Элемент класса T</returns>
public static T Map<TF, T>(TF from)
{
//Создаю элемент
// ReSharper disable once NullableWarningSuppressionIsUsed
T result = (T)Activator.CreateInstance(typeof(T))!;
//Сопоставляю по принципу "сопоставление всех параметров"
MapEx(from, ref result, MapMode.MapFull, new());
//Вывожу в результат
return result;
}
/// <summary>
/// Проверка выполнения условия
/// </summary>
/// <param name="itemName">Имя элемента</param>
/// <param name="itemValue">Значение элемента</param>
/// <param name="mode">Режим проверки</param>
/// <param name="list">Список игнорирования/добавления</param>
/// <returns></returns>
private static bool CheckCondition<T>(string itemName, object? itemValue, MapMode mode, ICollection<string> list)
{
//Если режим "Только список" и поля нет в списке,
//либо режим "Только не в списке" и поле есть в списке
//или режим "Только не пустые" и значение поля пустое,
//или режим "Только не по умолчанию" и значение по умолчанию
//то пропускаем
bool result =
mode switch
{
MapMode.MapFull => true,
MapMode.MapNotNull => itemValue != null,
MapMode.MapByList => list.Contains(itemName),
MapMode.MapIgnoreList => !list.Contains(itemName),
MapMode.MapNotDefault => itemValue != default,
MapMode.MapNotNullOrDefault => !Equals(itemValue, default(T)),
_ => throw new ArgumentOutOfRangeException(nameof(mode), mode, null)
};
//Возвращаем результат
return result;
}
/// <summary>
/// Перечисление типов сопоставления
/// </summary>
public enum MapMode
{
/// <summary>
/// Сопоставление всех параметров
/// </summary>
MapFull = 0,
/// <summary>
/// Сопоставление не пустых параметров
/// </summary>
MapNotNull = 1,
/// <summary>
/// Сопоставление по списку
/// </summary>
MapByList = 2,
/// <summary>
/// Сопоставление исключая список
/// </summary>
MapIgnoreList = 3,
/// <summary>
/// Сопоставление параметров, которые не равны значению по умолчанию
/// </summary>
MapNotDefault = 4,
/// <summary>
/// Сопоставление не пустых параметров, которые не равны значению по умолчанию (NotNull и NotDefault одновременно)
/// </summary>
MapNotNullOrDefault = 5,
}
}

View File

@ -1,15 +0,0 @@
using System.Text.Json;
using anbs_cp.Interfaces;
namespace anbs_cp.Classes;
/// <inheritdoc />
public class SysTextSerializer: ISerializer
{
/// <inheritdoc />
public string Serialize<T> (T data) => JsonSerializer.Serialize(data);
/// <inheritdoc />
public T? Deserialize<T> (string json) => JsonSerializer.Deserialize<T>(json);
}

View File

@ -1,128 +0,0 @@
using System.Net.Mail;
using System.Text.RegularExpressions;
namespace anbs_cp.Classes;
/// <summary>
/// Форматирование текста
/// </summary>
public static class TextFormatter
{
/// <summary>
/// Заменяет %МАРКЕРЫ% на их значения
/// </summary>
/// <param name="message">Текст сообщения</param>
/// <param name="replaceDictionary">Словарь замен</param>
/// <returns>Отформатированное сообщение</returns>
public static string FormatMessage (string message, Dictionary<string, string> replaceDictionary) =>
replaceDictionary.Aggregate(message,
static (current, item) => current.Replace($"%{item.Key}%", item.Value));
/// <summary>
/// Обрезает строку до указанных в параметре <paramref name="maxLength"/> символов
/// </summary>
/// <param name="text">Текст, который нужно обрезать</param>
/// <param name="maxLength">Максимальное количество символов в тексте</param>
/// <param name="endDots">Чем завершать обрезанный текст, если он был обрезан. Внимание расходует <see cref="maxLength"/>!</param>
/// <returns>Обрезанный текст</returns>
public static string GetShortText (string text, int maxLength, string endDots = "") =>
text.Length < maxLength ? text : $"{text[..(maxLength - endDots.Length)]}{endDots}";
/// <summary>
/// Генерирует случайный пароль, удовлетворяющий параметрам <see cref="PasswordOptions"/> <paramref name="options"/>.
/// Автор метода: Darkseal (https://stackoverflow.com/users/1233379/darkseal)
/// URL: https://stackoverflow.com/a/46229180/16469671
/// </summary>
/// <param name="options">Объект допустимых параметров пароля, содержащий требования к надежности пароля.</param>
/// <returns>Случайный пароль</returns>
public static string GenerateRandomPassword (PasswordOptions? options)
{
//Проверка options и установка по-умолчанию
options ??= new();
//Получаю массив символов
string[] randomChars = {
"ABCDEFGHJKLMNOPQRSTUVWXYZ", // прописные буквы
"abcdefghijkmnopqrstuvwxyz", // строчные буквы
"0123456789", // цифры
"~!@#$%^&*+-/.,{}[]();:|?<>='`" // символы
};
//Создаю объект Random
Random rand = new(Environment.TickCount);
//Массив результатов
List<char> chars = new();
//Вставляю прописные буквы
if (options.RequireUppercase)
chars.Insert(rand.Next(0, chars.Count),
randomChars[0][rand.Next(0, randomChars[0].Length)]);
//Вставляю строчные буквы
if (options.RequireLowercase)
chars.Insert(rand.Next(0, chars.Count),
randomChars[1][rand.Next(0, randomChars[1].Length)]);
//Вставляю цифры
if (options.RequireDigit)
chars.Insert(rand.Next(0, chars.Count),
randomChars[2][rand.Next(0, randomChars[2].Length)]);
//Вставляю символы
if (options.RequireNonAlphanumeric)
chars.Insert(rand.Next(0, chars.Count),
randomChars[3][rand.Next(0, randomChars[3].Length)]);
//Делаю выборку
for (int i = chars.Count; i < options.RequiredLength || chars.Distinct().Count() < options.RequiredUniqueChars; i++)
{
string rcs = randomChars[rand.Next(0, randomChars.Length)];
chars.Insert(rand.Next(0, chars.Count),
rcs[rand.Next(0, rcs.Length)]);
}
//Вывожу результат
return new(chars.ToArray());
}
/// <summary>
/// Проверяет <paramref name="email"/> на соответствие критерию электронной почты
/// Взято с: https://stackoverflow.com/a/1374644/16469671
/// </summary>
/// <param name="email">Проверяемая строка</param>
/// <returns>Является ли <paramref name="email"/> адресом электронной почты</returns>
public static bool IsValidEmail (string email)
{
string trimmedEmail = email.Trim();
if (trimmedEmail.EndsWith(".", StringComparison.Ordinal))
return false;
try
{
MailAddress addr = new(email);
return addr.Address == trimmedEmail;
}
catch
{
return false;
}
}
/// <summary>
/// Проверяет текст <paramref name="text"/> на совпадение регулярному выражению по шаблону <paramref name="pattern"/> с опциями <paramref name="options"/> (см. <see cref="RegexOptions"/>)
/// </summary>
/// <param name="text">Текст на проверку</param>
/// <param name="pattern">Шаблон</param>
/// <param name="options">Параметры проверки в формате <see cref="RegexOptions"/> (можно игнорировать, по умолчанию: <see cref="RegexOptions.IgnoreCase"/>)</param>
/// <returns>Есть ли совпадения в тексте</returns>
public static bool IsMatchRegExp (string text, string pattern, RegexOptions? options = null)
{
// Задаю настройки проверки регулярных выражений
RegexOptions regexOptions = options ?? RegexOptions.IgnoreCase;
// Возвращаю результат
return Regex.IsMatch(text, pattern, regexOptions);
}
}

View File

@ -1,90 +0,0 @@
namespace anbs_cp.Classes;
/// <summary>
/// Класс проверки временного интервала
/// </summary>
public static class TimestampValidator
{
/// <summary>
/// Проверка попадания в заданный интервал (в мс)
/// </summary>
/// <param name="timestamp">Временной интервал</param>
/// <param name="checkedStamp">Проверяемый временной интервал</param>
/// <param name="deltaMs">Временная дельта в миллисекундах</param>
/// <returns>
/// Попал ли <paramref name="checkedStamp" /> в промежуток <paramref name="timestamp" /> +
/// <paramref name="deltaMs" />
/// </returns>
public static bool Validate(long timestamp, long checkedStamp, ulong deltaMs) =>
new TimeSpan(timestamp) + TimeSpan.FromMilliseconds(deltaMs) > new TimeSpan(checkedStamp);
/// <summary>
/// Проверка попадания текущего времени в заданный интервал (в мс)
/// </summary>
/// <param name="timestamp">Временной интервал</param>
/// <param name="deltams">Временная дельта в миллисекундах</param>
/// <returns>Попадает ли текущее время в промежуток <paramref name="timestamp" /> + <paramref name="deltams" /></returns>
public static bool ValidateNow(long timestamp, ulong deltams) =>
Validate(timestamp, DateTime.UtcNow.Ticks, deltams);
/// <summary>
/// Проверка временного интервала (в сек)
/// </summary>
/// <param name="timestamp">Временной интервал</param>
/// <param name="checkedstamp">Проверяемый временной интервал</param>
/// <param name="deltasec">Временная дельта в секундах</param>
/// <returns>Попал ли <see cref="checkedstamp" /> в промежуток</returns>
public static bool ValidateFromSec(long timestamp, long checkedstamp, ulong deltasec) =>
Validate(timestamp, checkedstamp, checked(deltasec * 1000UL));
/// <summary>
/// Проверка попадания текущего времени в заданный интервал (в сек)
/// </summary>
/// <param name="timestamp">Временной интервал</param>
/// <param name="deltasec">Временная дельта в секундах</param>
/// <returns>Попадает ли текущее время в промежуток <paramref name="timestamp" /> + <paramref name="deltasec" /></returns>
public static bool ValidateFromSecNow(long timestamp, ulong deltasec) =>
ValidateFromSec(timestamp, DateTime.UtcNow.Ticks, deltasec);
/// <summary>
/// Проверка временного интервала (в мин)
/// </summary>
/// <param name="timestamp">Временной интервал</param>
/// <param name="checkedstamp">Проверяемый временной интервал</param>
/// <param name="deltamin">Временная дельта в минутах</param>
/// <returns>
/// Попал ли <see cref="checkedstamp" /> в промежуток <paramref name="timestamp" /> + <paramref name="deltamin" />
/// </returns>
public static bool ValidateFromMin(long timestamp, long checkedstamp, ulong deltamin) =>
Validate(timestamp, checkedstamp, checked(deltamin * 60000UL));
/// <summary>
/// Проверка попадания текущего времени в заданный интервал (в мин)
/// </summary>
/// <param name="timestamp">Временной интервал</param>
/// <param name="deltamin">Временная дельта в минутах</param>
/// <returns>Попадает ли текущее время в промежуток <paramref name="timestamp" /> + <paramref name="deltamin" /></returns>
public static bool ValidateFromMinNow(long timestamp, ulong deltamin) =>
ValidateFromMin(timestamp, DateTime.UtcNow.Ticks, deltamin);
/// <summary>
/// Проверка временного интервала (в час)
/// </summary>
/// <param name="timestamp">Временной интервал</param>
/// <param name="checkedStamp">Проверяемый временной интервал</param>
/// <param name="deltaHour">Временная дельта в часах</param>
/// <returns>
/// Попал ли <see cref="checkedStamp" /> в промежуток <paramref name="timestamp" /> + <paramref name="deltaHour" />
/// </returns>
public static bool ValidateFromHour(long timestamp, long checkedStamp, ulong deltaHour) =>
Validate(timestamp, checkedStamp, checked(deltaHour * 3600000UL));
/// <summary>
/// Проверка попадания текущего времени в заданный интервал (в час)
/// </summary>
/// <param name="timestamp">Временной интервал</param>
/// <param name="deltahr">Временная дельта в часах</param>
/// <returns>Попадает ли текущее время в промежуток <paramref name="timestamp" /> + <paramref name="deltahr" /></returns>
public static bool ValidateFromHourNow(long timestamp, ulong deltahr) =>
ValidateFromHour(timestamp, DateTime.UtcNow.Ticks, deltahr);
}

View File

@ -1,163 +0,0 @@
using System.Globalization;
namespace anbs_cp.Classes;
/// <summary>
/// Конвертер типов на манер Delphi
/// </summary>
public static class TypeConverter
{
#region Конвертация числа в строку
/// <summary>
/// Преобразование <see cref="int"/> в <see cref="string"/>
/// </summary>
/// <param name="value">Число</param>
/// <returns>Значение в <see cref="string"/></returns>
public static string IntToStr (int value) => value.ToString();
/// <summary>
/// Преобразование <see cref="uint"/> в <see cref="string"/>
/// </summary>
/// <param name="value">Число</param>
/// <returns>Значение в <see cref="string"/></returns>
public static string IntToStr (uint value) => value.ToString();
/// <summary>
/// Преобразование <see cref="long"/> в <see cref="string"/>
/// </summary>
/// <param name="value">Число</param>
/// <returns>Значение в <see cref="string"/></returns>
public static string IntToStr (long value) => value.ToString();
/// <summary>
/// Преобразование <see cref="ulong"/> в <see cref="string"/>
/// </summary>
/// <param name="value">Число</param>
/// <returns>Значение в <see cref="string"/></returns>
public static string IntToStr (ulong value) => value.ToString();
/// <summary>
/// Преобразование <see cref="byte"/> в <see cref="string"/>
/// </summary>
/// <param name="value">Число</param>
/// <returns>Значение в <see cref="string"/></returns>
public static string IntToStr (byte value) => value.ToString();
/// <summary>
/// Преобразование <see cref="decimal"/> в <see cref="string"/>
/// </summary>
/// <param name="value">Число</param>
/// <returns>Значение в <see cref="string"/></returns>
public static string DecimalToStr (decimal value) => value.ToString(CultureInfo.InvariantCulture);
/// <summary>
/// Преобразование <see cref="double"/> в <see cref="string"/>
/// </summary>
/// <param name="value">Число</param>
/// <returns>Значение в <see cref="string"/></returns>
public static string DoubleToStr (double value) => value.ToString(CultureInfo.InvariantCulture);
/// <summary>
/// Преобразование <see cref="bool"/> в <see cref="string"/>
/// </summary>
/// <param name="value">Значение правда/ложь</param>
/// <returns>Значение в <see cref="string"/></returns>
public static string BoolToStr (bool value) => value.ToString();
/// <summary>
/// Преобразование любого типа в <see cref="string"/> (сериализация)
/// </summary>
/// <typeparam name="T">Тип</typeparam>
/// <param name="value">Значение типа</param>
/// <returns>Значение в <see cref="string"/></returns>
public static string TypeToStr<T> (T value) => new SysTextSerializer().Serialize(value);
#endregion
#region Конвертация строки в число
/// <summary>
/// Преобразование <see cref="string"/> в <see cref="int"/>
/// </summary>
/// <param name="value">Строка</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Значение в <see cref="int"/></returns>
public static int StrToInt (string value, int defaultValue = 0) =>
int.TryParse(value, out int result) ? result : defaultValue;
/// <summary>
/// Преобразование <see cref="string"/> в <see cref="uint"/>
/// </summary>
/// <param name="value">Строка</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Значение в <see cref="uint"/></returns>
public static uint StrToUInt (string value, uint defaultValue = 0) =>
uint.TryParse(value, out uint result) ? result : defaultValue;
/// <summary>
/// Преобразование <see cref="string"/> в <see cref="long"/>
/// </summary>
/// <param name="value">Строка</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Значение в <see cref="long"/></returns>
public static long StrToInt64 (string value, long defaultValue = 0) =>
long.TryParse(value, out long result) ? result : defaultValue;
/// <summary>
/// Преобразование <see cref="string"/> в <see cref="ulong"/>
/// </summary>
/// <param name="value">Строка</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Значение в <see cref="ulong"/></returns>
public static ulong StrToUInt64 (string value, ulong defaultValue = 0) =>
ulong.TryParse(value, out ulong result) ? result : defaultValue;
/// <summary>
/// Преобразование <see cref="string"/> в <see cref="byte"/>
/// </summary>
/// <param name="value">Строка</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Значение в <see cref="byte"/></returns>
public static byte StrToByte (string value, byte defaultValue = byte.MinValue) =>
byte.TryParse(value, out byte result) ? result : defaultValue;
/// <summary>
/// Преобразование <see cref="string"/> в <see cref="decimal"/>
/// </summary>
/// <param name="value">Строка</param>
/// <param name="defaultValue">Значение по умолчанию (<see cref="decimal.Zero"/>)</param>
/// <returns>Значение в <see cref="decimal"/></returns>
public static decimal StrToDecimal (string value, decimal defaultValue = decimal.Zero) =>
decimal.TryParse(value, out decimal result) ? result : defaultValue;
/// <summary>
/// Преобразование <see cref="string"/> в <see cref="double"/>
/// </summary>
/// <param name="value">Строка</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Значение в <see cref="double"/></returns>
public static double StrToDouble (string value, double defaultValue = 0) =>
double.TryParse(value, out double result) ? result : defaultValue;
/// <summary>
/// Преобразование <see cref="string"/> в <see cref="bool"/>
/// </summary>
/// <param name="value">Строка</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Значение в <see cref="bool"/></returns>
public static bool StrToBool (string value, bool defaultValue = false) =>
bool.TryParse(value, out bool result) ? result : defaultValue;
/// <summary>
/// Преобразование <see cref="string"/> в тип <see cref="T"/> (десериализация)
/// </summary>
/// <typeparam name="T">Тип</typeparam>
/// <param name="value">Строка</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Значение в <see cref="T"/></returns>
public static T StrToType<T>(string value, T defaultValue) =>
new SysTextSerializer().Deserialize<T>(value) ?? defaultValue;
#endregion
}

View File

@ -1,79 +0,0 @@
using anbs_cp.Interfaces;
namespace anbs_cp.Classes;
/// <summary>
/// Абстрактный класс конвертера величин для отображения (улучшенный аналог ValueFormatter)
/// </summary>
/// <param name="valueNames">Массив имён размерностей</param>
/// <param name="divider">Делитель</param>
/// <param name="decimalPlaces">Число знаков после запятой</param>
public abstract class ValueConverter (IEnumerable<string> valueNames, long divider, byte decimalPlaces): IValueConverter
{
#region Реализация интерфейса
/// <summary>
/// Массив имён размерностей
/// </summary>
public string[] ValueNames { get; init; } = valueNames.ToArray();
/// <summary>
/// Делитель
/// </summary>
public long Divider { get; init; } = divider;
/// <summary>
/// Знаков после запятой (0, 1, 2)
/// </summary>
public byte DecimalPlaces { get; init; } = (byte)(decimalPlaces < 3 ? decimalPlaces : 2);
#endregion
#region Методы
/// <summary>
/// Функция конвертирования в строку
/// </summary>
/// <param name="value">Значение</param>
/// <returns>Конвертирование значение в строку</returns>
public string Convert (long value)
{
//Получаю разделенное значение
(decimal, int) result = DivideIt(value, 0);
//Преобразую значение в строку
string resultValue = DecimalPlaces switch
{
0 => $"{result.Item1:F0}",
1 => $"{result.Item1:F1}",
_ => $"{result.Item1:F2}"
};
//Возвращаю результат
return $"{resultValue} {ValueNames[result.Item2]}";
}
/// <summary>
/// Рекурсивная функция деления
/// </summary>
/// <param name="value">Число</param>
/// <param name="count">Счётчик вызова рекурсии</param>
/// <returns>Число в остатке и количество вызовов рекурсии</returns>
private (decimal, int) DivideIt (decimal value, int count)
{
//Если счёт уже больше количества названий
if (count > ValueNames.Length)
return (value, count);
//Если частное уже меньше делителя, то прерываем цикл
if (value < Divider)
return (value, count);
//Увеличиваем счётчик...
count++;
//... и продолжаем цикл
return DivideIt(value / Divider, count);
}
#endregion
}

34
anbs_cp/CountFormatter.cs Normal file
View File

@ -0,0 +1,34 @@
namespace anbs_cp
{
/// <summary>
/// Форматирует число элементов в понятную строку
/// </summary>
public class CountFormatter : IValueFormatter
{
#region ойства класса
/// <summary>
/// Имена чисел (тысяч, миллионов, миллиардов и т.п.)
/// </summary>
public string[] CountNames { get; set; } = { "", "тыс.", "млн.", "млрд." };
/// <summary>
/// Знаков после запятой
/// </summary>
public byte DecimalPlaces { get; set; } = 1;
/// <summary>
/// Делители чисел
/// </summary>
public long[] Delimeters { get; set; } = { 1000, 1000000, 1000000000 };
#endregion
#region Реализация интерфейса
/// <summary>
/// Реализация интерфейса
/// </summary>
public string[] ValueNames { get => CountNames; set => CountNames = value; }
/// <summary>
/// Реализация интерфейса
/// </summary>
public long[] MaxSizes { get => Delimeters; set => Delimeters = value; }
#endregion
}
}

View File

@ -1,21 +0,0 @@
namespace anbs_cp.Enums;
/// <summary>
/// Тип сообщения о состоянии
/// </summary>
public enum EActionStateMessageType
{ /// <summary>
/// Информация
/// </summary>
Information = 0,
/// <summary>
/// Предупреждение
/// </summary>
Warning = 1,
/// <summary>
/// Ошибка
/// </summary>
Error = 2
}

View File

@ -1,32 +0,0 @@
namespace anbs_cp.Enums;
/// <summary>
/// Область печати состояния действия
/// </summary>
public enum EActionStatePrintArea
{
/// <summary>
/// Все (сообщения, предупреждения, ошибки)
/// </summary>
All = 0,
/// <summary>
/// Только предупреждения и ошибки
/// </summary>
ErrorsAndWarnings = 1,
/// <summary>
/// Только ошибки
/// </summary>
ErrorsOnly = 2,
/// <summary>
/// Только предупреждения
/// </summary>
WarningsOnly = 3,
/// <summary>
/// Только информационные сообщения
/// </summary>
InfosOnly = 4
}

View File

@ -1,32 +0,0 @@
namespace anbs_cp.Enums;
/// <summary>
/// Действия при операции переименования, если файл существует
/// </summary>
public enum EOnExistAction
{
/// <summary>
/// Возбуждать исключение
/// </summary>
RaiseException = 0,
/// <summary>
/// Прервать операцию
/// </summary>
Abort = 1,
/// <summary>
/// Продолжить операцию
/// </summary>
Ignore = 2,
/// <summary>
/// Возбуждать исключение, если папка не пуста (только для папок)
/// </summary>
RaiseExceptionIfNotEmpty = 3,
/// <summary>
/// Прервать операцию, если папка не пуста (только для папок)
/// </summary>
AbortIfNotEmpty = 4
}

View File

@ -1,17 +0,0 @@
namespace anbs_cp.Enums;
/// <summary>
/// Действие, которое привело к ошибке сериализации
/// </summary>
public enum ESerializeExceptionAction
{
/// <summary>
/// Сериализация
/// </summary>
Serialize = 0,
/// <summary>
/// Десериализация
/// </summary>
Deserialize = 1
}

View File

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

View File

@ -1,28 +0,0 @@
using anbs_cp.Enums;
namespace anbs_cp.Exceptions;
/// <summary>
/// Ошибка (де)сериализации
/// </summary>
/// <param name="action">Действие сериализатора, приведшее к ошибке</param>
/// <param name="objectJson">Объект сериализации при сериализации или строка json при десериализации</param>
/// <param name="message">Сообщение пользователю</param>
public sealed class SerializeException (ESerializeExceptionAction action, string? objectJson, string? message = null)
: Exception(message)
{
/// <summary>
/// Действие сериализатора, приведшее к ошибке
/// </summary>
public ESerializeExceptionAction Action => action;
/// <summary>
/// Объект сериализации (при action == ESerializeExceptionAction.Serialize)
/// </summary>
public string? Object => action == ESerializeExceptionAction.Serialize ? objectJson : null;
/// <summary>
/// Строка json при десериализации
/// </summary>
public string? Json => action == ESerializeExceptionAction.Deserialize ? objectJson : null;
}

View File

@ -1,32 +0,0 @@
namespace anbs_cp.Extensions;
/// <summary>
/// Расширение типа "правда/ложь"
/// </summary>
public static class BooleanExtensions
{
/// <summary>
/// Вывод в строку <paramref name="ifTrue"/>, если выражение <paramref name="b"/> правдиво и
/// <paramref name="ifFalse"/> в противном случае.
/// </summary>
/// <param name="b">Выражение типа правда/ложь</param>
/// <param name="ifTrue">Строка для правдивого выражения</param>
/// <param name="ifFalse">Строка для лживого выражения</param>
/// <returns>Вывод строки</returns>
public static string ExportToString (this bool b, string ifTrue, string ifFalse) => b ? ifTrue : ifFalse;
/// <summary>
/// Вычисляет количество булевых переменных <paramref name="expressions"/> в значении true.
/// </summary>
/// <param name="expressions">Переменные</param>
/// <returns>Количество переменных в значении true</returns>
public static int TrueCount (params bool[] expressions) => expressions.Count(static b => b);
/// <summary>
/// Вычисляет, есть ли хотя бы одно из булевых переменных <paramref name="expressions"/> в значении true.
/// </summary>
/// <param name="expressions">Переменные</param>
/// <returns>Есть ли хотя бы одно в значении true</returns>
public static bool AnyTrue (params bool[] expressions) => TrueCount(expressions) > 0;
}

View File

@ -1,15 +0,0 @@
namespace anbs_cp.Extensions;
/// <summary>
/// Расширение класса DateTime
/// </summary>
public static class DateTimeExtension
{
/// <summary>
/// "Обнуляет" миллисекунды
/// </summary>
/// <param name="dt">Дата/время</param>
/// <returns>Дата/время с нулевыми миллисекундами</returns>
public static DateTime TrimMilliseconds (this DateTime dt) =>
new(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, 0, dt.Kind);
}

View File

@ -1,15 +0,0 @@
using System.Text;
namespace anbs_cp.Extensions;
/// <summary>
/// Класс-расширение для Encoding
/// </summary>
public static class EncodingExtensions
{
/// <summary>
/// Кодировка UTF8 без Bom
/// </summary>
// ReSharper disable once InconsistentNaming
public static Encoding UTF8WithoutBom (this Encoding encoding) => new UTF8Encoding(false);
}

View File

@ -1,172 +0,0 @@
// ReSharper disable MemberCanBePrivate.Global
using anbs_cp.Classes;
using System.Text;
namespace anbs_cp.Extensions;
/// <summary>
/// Класс -- расширение для класса File
/// </summary>
public static class FileExtension
{
/// <summary>
/// Получает MIME-тип файла
/// </summary>
/// <param name="filename">Имя файла</param>
/// <returns>MIME-тип файла</returns>
public static string MimeType (string filename) =>
MimeTypes.GetMimeType(filename);
/// <summary>
/// Размер файла в байтах
/// </summary>
/// <param name="fileName">Полное имя и путь к файлу</param>
/// <returns>Размер файла в байтах</returns>
public static long FileSize (string fileName) =>
new FileInfo(fileName).Length;
/// <summary>
/// Получает хэш файла
/// </summary>
/// <param name="fileName">Имя файла</param>
/// <returns>Хэш файла в формате <see cref="FileHash"/></returns>
public static FileHash GetHash (string fileName) =>
new(fileName);
/// <summary>
/// Получение содержимого файла
/// </summary>
/// <param name="fileName">Имя файла</param>
/// <returns>Содержимое файла</returns>
public static byte[] GetFileContent (string fileName) => File.ReadAllBytes(fileName);
#region Write
/// <summary>
/// Записывает данные <paramref name="data"/> в текстовый файл <paramref name="fileName"/>
/// </summary>
/// <typeparam name="T">Тип данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="fileName">Имя файла</param>
/// <param name="encoding">Кодировка</param>
public static void Write<T> (T data, string fileName, Encoding encoding)
{
// Открываю файл для создания или перезаписи
using StreamWriter writer = new(new FileStream(fileName, FileMode.OpenOrCreate), encoding);
// Записываю
writer.WriteLine(new NewtonsoftJsonSerializer().Serialize(data));
}
/// <summary>
/// Записывает данные <paramref name="data"/> в текстовый файл <paramref name="fileName"/>
/// </summary>
/// <typeparam name="T">Тип данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="fileName">Имя файла</param>
/// <param name="useUtf8WithBom">Нужно ли использовать кодировку UTF8 With BOM или UTF8 Without BOM</param>
public static void Write<T> (T data, string fileName, bool useUtf8WithBom = false) => Write(data, fileName,
useUtf8WithBom ? Encoding.UTF8 : Encoding.UTF8.UTF8WithoutBom());
/// <summary>
/// Записывает все данные из списка <paramref name="data"/> в текстовый файл <paramref name="fileName"/>
/// </summary>
/// <param name="data">Данные</param>
/// <param name="fileName">Имя файла</param>
/// <param name="encoding">Кодировка файла</param>
/// <typeparam name="T">Тип данных</typeparam>
public static void WriteAll<T> (IEnumerable<T> data, string fileName, Encoding encoding)
{
// Открываю файл для создания или перезаписи
using StreamWriter writer = new(new FileStream(fileName, FileMode.OpenOrCreate), encoding);
// Для каждого элемента списка
foreach (T element in data)
// - записываю его строкой в файл
writer.WriteLine(new NewtonsoftJsonSerializer().Serialize(element));
}
/// <summary>
/// Записывает все данные из списка <paramref name="data"/> в текстовый файл <paramref name="fileName"/>
/// </summary>
/// <param name="data">Данные</param>
/// <param name="fileName">Имя файла</param>
/// <param name="useUtf8WithBom">Нужно ли использовать кодировку UTF8 With BOM или UTF8 Without BOM</param>
/// <typeparam name="T">Тип данных</typeparam>
public static void WriteAll<T> (IEnumerable<T> data, string fileName, bool useUtf8WithBom = false) =>
WriteAll(data, fileName, useUtf8WithBom ? Encoding.UTF8 : Encoding.UTF8.UTF8WithoutBom());
#endregion
#region Read
/// <summary>
/// Читает первую строку из текстового файла <paramref name="fileName"/>
/// </summary>
/// <param name="fileName">Имя файла</param>
/// <param name="encoding">Кодировка файла</param>
/// <typeparam name="T">Тип выходных данных</typeparam>
/// <returns>Данные или null</returns>
public static T? Read<T> (string fileName, Encoding encoding)
{
// Открываю файл для чтения
using StreamReader reader = new(new FileStream(fileName, FileMode.Open), encoding);
// Считываю первую запись
string serialized = reader.ReadLine() ?? "{}";
// Возвращаю конвертированный тип
return new NewtonsoftJsonSerializer().Deserialize<T>(serialized);
}
/// <summary>
/// Читает первую строку из текстового файла <paramref name="fileName"/>
/// </summary>
/// <param name="fileName">Имя файла</param>
/// <param name="useUtf8WithBom">Нужно ли использовать кодировку UTF8 With BOM или UTF8 Without BOM</param>
/// <typeparam name="T">Тип выходных данных</typeparam>
/// <returns>Данные или null</returns>
public static T? Read<T> (string fileName, bool useUtf8WithBom = false) => Read<T>(fileName,
useUtf8WithBom ? Encoding.UTF8 : Encoding.UTF8.UTF8WithoutBom());
/// <summary>
/// Читает все строки из текстового файла <paramref name="fileName"/>
/// </summary>
/// <param name="fileName">Имя файла</param>
/// <param name="encoding">Кодировка файла</param>
/// <typeparam name="T">Тип выходных данных</typeparam>
/// <returns>Список данных</returns>
public static IEnumerable<T> ReadAll<T> (string fileName, Encoding encoding)
{
// Создаю результат
List<T> result = [];
// Открываю файл для чтения
using StreamReader reader = new(new FileStream(fileName, FileMode.Open), encoding);
// Пока есть строки в файле
while (reader.ReadLine() is { } serialized)
{
// - десериализую их
T? data = new NewtonsoftJsonSerializer().Deserialize<T>(serialized);
// - и если они не нулевые
if (data is not null)
// -- то добавляю их в результат
result.Add(data);
}
// Возвращаю полученный список
return result.AsEnumerable();
}
/// <summary>
/// Читает все строки из текстового файла <paramref name="fileName"/>
/// </summary>
/// <param name="fileName">Имя файла</param>
/// <param name="useUtf8WithBom">Нужно ли использовать кодировку UTF8 With BOM или UTF8 Without BOM</param>
/// <typeparam name="T">Тип выходных данных</typeparam>
/// <returns>Список данных</returns>
public static IEnumerable<T> ReadAll<T> (string fileName, bool useUtf8WithBom = false) =>
ReadAll<T>(fileName, useUtf8WithBom ? Encoding.UTF8 : Encoding.UTF8.UTF8WithoutBom());
#endregion
}

View File

@ -1,69 +0,0 @@
using System.Diagnostics.CodeAnalysis;
namespace anbs_cp.Extensions;
/// <summary>
/// Расширение Guid
/// </summary>
public static class GuidExtensions
{
/// <summary>
/// Проверяет Guid на пустоту
/// </summary>
/// <param name="g">Guid или null</param>
/// <returns>Guid пуст (null) или равен Guid.Empty</returns>
public static bool IsNullOrEmpty ([NotNullWhen(false)] this Guid? g) => g == null || g == Guid.Empty;
/// <summary>
/// Проверяет Guid на пустоту
/// </summary>
/// <param name="g">Guid</param>
/// <returns>Guid пуст (null) или равен Guid.Empty</returns>
public static bool IsNullOrEmpty (this Guid g) => g == Guid.Empty;
/// <summary>
/// Генерирует <see cref="Guid"/>, удовлетворяющий условию <paramref name="predicate"/>
/// </summary>
/// <param name="predicate">Условие генерации <see cref="Guid"/></param>
/// <returns>Новый <see cref="Guid"/></returns>
public static Guid GenerateGuid (Func<Guid, bool> predicate)
{
// Задаю GUID
Guid guid;
// Выполняй
do
{
// - генерируй GUID
guid = Guid.NewGuid();
}
// - пока не выполнено условие
while (!predicate(guid));
// Возвращаю сгенерированный GUID
return guid;
}
/// <summary>
/// Генерирует <see cref="Guid"/>, удовлетворяющий условию <paramref name="asyncPredicate"/>
/// </summary>
/// <param name="asyncPredicate">Условие генерации <see cref="Guid"/></param>
/// <returns>Новый <see cref="Guid"/></returns>
public static async Task<Guid> GenerateGuidAsync (Func<Guid, Task<bool>> asyncPredicate)
{
// Задаю GUID
Guid guid;
// Выполняй
do
{
// - генерируй GUID
guid = Guid.NewGuid();
}
// - пока не выполнено условие
while (!await asyncPredicate(guid));
// Возвращаю сгенерированный GUID
return guid;
}
}

View File

@ -1,83 +0,0 @@
using System.Text;
namespace anbs_cp.Extensions;
/// <summary>
/// Класс-расширение для List
/// </summary>
public static class ListExtensions
{
/// <summary>
/// Загрузка строк из текстового файла
/// </summary>
/// <param name="list">Список, в который нужно загрузит</param>
/// <param name="fileName">Имя файла, который нужно загрузить</param>
/// <param name="useUtf8WithBom">Использовать кодировку UTF8 With Bom</param>
public static void LoadFromFile (this List<string> list, string fileName, bool useUtf8WithBom = false)
{
// Очищаю список
list.Clear();
// Кодировка
Encoding fileEncoding =
useUtf8WithBom ? Encoding.UTF8 : Encoding.UTF8.UTF8WithoutBom();
// Открываю файл для чтения
using StreamReader reader = new(new FileStream(fileName, FileMode.Open), fileEncoding);
// Пока есть строки в файле
while (reader.ReadLine() is { } line)
// - добавляю в список
list.Add(line);
}
/// <summary>
/// Загрузка строк из типизированного файла
/// </summary>
/// <typeparam name="T">Тип данных</typeparam>
/// <param name="list">Список, в который нужно загрузит</param>
/// <param name="fileName">Имя файла, который нужно загрузить</param>
/// <param name="encoding">Кодировка файла</param>
public static void LoadFromFile<T> (this List<T> list, string fileName, Encoding encoding)
{
// Очищаю список
list.Clear();
// Добавляю в список загруженные строки
list.AddRange(FileExtension.ReadAll<T>(fileName, encoding));
}
/// <summary>
/// Сохранение списка строк в файл
/// </summary>
/// <param name="list">Список</param>
/// <param name="fileName">Имя файла</param>
/// <param name="useUtf8WithBom">Использовать кодировку UTF8 With Bom</param>
public static void SaveToFile (this List<string> list, string fileName, bool useUtf8WithBom = false)
{
// Очищаю список
list.Clear();
// Кодировка
Encoding fileEncoding =
useUtf8WithBom ? Encoding.UTF8 : Encoding.UTF8.UTF8WithoutBom();
// Открываю файл для создания или перезаписи
using StreamWriter writer = new(new FileStream(fileName, FileMode.OpenOrCreate), fileEncoding);
// Для каждой строки
foreach (string line in list)
// - записываю её
writer.WriteLine(line);
}
/// <summary>
/// Сохранение списка строк в файл
/// </summary>
/// <typeparam name="T">Тип данных</typeparam>
/// <param name="list">Список</param>
/// <param name="fileName">Имя файла</param>
/// <param name="encoding">Кодировка файла</param>
public static void SaveToFile<T> (this List<T> list, string fileName, Encoding encoding) =>
FileExtension.WriteAll(list.AsEnumerable(), fileName, encoding);
}

View File

@ -1,16 +0,0 @@
using System.Reflection;
namespace anbs_cp.Extensions;
/// <summary>
/// Расширение MethodInfo
/// </summary>
public static class MethodInfoExtension
{
/// <summary>
/// Проверяет, является ли метод асинхронным
/// </summary>
/// <param name="method">Метод</param>
/// <returns>Асинхронный или нет</returns>
public static bool IsAsync (this MethodInfo method) => typeof(Task) == method.ReturnType;
}

View File

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

View File

@ -0,0 +1,56 @@
namespace anbs_cp
{
/// <summary>
/// Форматирует размер файла/папки в понятную строку
/// </summary>
public class FileSizeFormatter : IValueFormatter
{
#region ойства класса
/// <summary>
/// Имена размеров (байт, килобайт, мегабайт, гигабайт и террабайт)
/// </summary>
public string[] SizeNames { get; set; } = { "Байт", "Кб", "Мб", "Гб", "Тб" };
/// <summary>
/// Знаков после запятой
/// </summary>
public byte DecimalPlaces { get; set; } = 2;
/// <summary>
/// Максимально байт (далее идут Кбайты)
/// </summary>
public long ByteMax { get; set; } = 1024;
/// <summary>
/// Максимально Кбайт (далее идут Мбайты)
/// </summary>
public long KByteMax { get; set; } = 1048576;
/// <summary>
/// Максимально Мбайт (далее идут Гбайты)
/// </summary>
public long MByteMax { get; set; } = 1073741824;
/// <summary>
/// Максимально Гбайт (далее идут Тбайты)
/// </summary>
public long GByteMax { get; set; } = 1099511627776;
#endregion
#region Реализация интерфейса
/// <summary>
/// Реализация интерфейса
/// </summary>
public string[] ValueNames { get => SizeNames; set => SizeNames = value; }
/// <summary>
/// Реализация интерфейса
/// </summary>
public long[] MaxSizes
{
get => new long[] { ByteMax, KByteMax, MByteMax, GByteMax };
set
{
ByteMax = value[0];
KByteMax = value[1];
MByteMax = value[2];
GByteMax = value[3];
}
}
#endregion
}
}

View File

@ -0,0 +1,82 @@
namespace anbs_cp
{
/// <summary>
/// Форматирует размерности в понятную строку
/// </summary>
public interface IValueFormatter
{
#region Определения интерфейса
/// <summary>
/// Имена размерностей
/// </summary>
public string[] ValueNames { get; set; }
/// <summary>
/// Знаков после запятой
/// </summary>
public byte DecimalPlaces { get; set; }
/// <summary>
/// Максимальные размеры (массив ulong[4])
/// </summary>
public long[] MaxSizes { get; set; }
#endregion
#region Методы интерфейса
/// <summary>
/// Форматирование размерности
/// </summary>
/// <param name="value">Размерность, требующая форматирования</param>
/// <returns>Форматированная размерность (например, 20 Мб)</returns>
public string Format(long value)
{
//Левая граница
long leftnum;
//Правая граница
long rightnum;
for (int i = 0; i <= MaxSizes.Length; i++)
{
if (i == 0)
leftnum = 0;
else
leftnum = MaxSizes[i - 1];
if (i == MaxSizes.Length)
rightnum = long.MaxValue;
else
rightnum = MaxSizes[i];
if ((value >= leftnum) && (value < rightnum))
return $"{FormatValue(value, leftnum)} {ValueNames[i]}";
}
return value.ToString();
}
/// <summary>
/// Деление числа на число с DecimalPlaces знаками после запятой
/// </summary>
/// <param name="dividend">Делимое число</param>
/// <param name="divider">Число-делитель</param>
/// <returns>Частное (с DecimalPlaces знаками после запятой)</returns>
private string FormatValue(long dividend, long divider)
{
if (divider == 0)
{
return $"{dividend}";
}
long delim = 1;
for (int i = 0; i <= DecimalPlaces; i++)
{
delim *= 10;
}
decimal value = Math.Round((decimal)(dividend * delim / divider)) / delim;
return $"{value}";
}
#endregion
}
}

View File

@ -1,41 +0,0 @@
namespace anbs_cp.Interfaces;
/// <summary>
/// Интерфейс шифрования
/// </summary>
public interface IEncryptor
{
/// <summary>
/// Метод для шифрования строки <paramref name="value"/>
/// </summary>
/// <param name="value">Строка, которая должна быть зашифрована</param>
/// <param name="salt">Ключ шифрования</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>Этот метод возвращает зашифрованную строку <paramref name="value"/></returns>
string Encrypt (string value, string salt, string valueIfFail);
/// <summary>
/// Метод для дешифрования строки <paramref name="encryptedValue"/>
/// </summary>
/// <param name="encryptedValue">Строка, которая должна быть дешифрована</param>
/// <param name="salt">Ключ шифрования</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>Этот метод возвращает дешифрованную строку <paramref name="encryptedValue"/></returns>
string Decrypt (string encryptedValue, string salt, string valueIfFail);
/// <summary>
/// Декодирует зашифрованную строку в HTML-пригодный формат
/// </summary>
/// <param name="text">Зашифрованная строка</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>Этот метод возвращает дешифрованную строку <paramref name="text"/></returns>
string Base64UrlEncode (string text, string valueIfFail);
/// <summary>
/// Раскодирует из декодированной строки в HTML-пригодный формат
/// </summary>
/// <param name="text">Декодированная строка</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>Этот метод возвращает шифрованную строку <paramref name="text"/></returns>
string Base64UrlDecode (string text, string valueIfFail);
}

View File

@ -1,23 +0,0 @@
using anbs_cp.Exceptions;
namespace anbs_cp.Interfaces;
/// <summary>
/// Интерфейс для сериализации объектов
/// </summary>
public interface ISerializable
{
/// <summary>
/// Сериализовать элемент в формат json
/// </summary>
/// <returns>Строка в формате json</returns>
/// <exception cref="SerializeException">Ошибка при сериализации</exception>
string Serialize();
/// <summary>
/// Восстановить элемент из формата json
/// </summary>
/// <param name="json">Строка в формате json</param>
/// <exception cref="SerializeException">Ошибка при десериализации</exception>
void Deserialize(string json);
}

View File

@ -1,23 +0,0 @@
namespace anbs_cp.Interfaces;
/// <summary>
/// Сериализация моделей, классов и других объектов
/// </summary>
public interface ISerializer
{
/// <summary>
/// Сериализация данных <paramref name="data"/> в строку.
/// </summary>
/// <typeparam name="T">Тип данных</typeparam>
/// <param name="data">Данные</param>
/// <returns>Сериализованные данные</returns>
string Serialize<T> (T data);
/// <summary>
/// Десериализация данных из json-строки <paramref name="json"/>
/// </summary>
/// <typeparam name="T">Ожидаемый тип данных</typeparam>
/// <param name="json">Сериализованные данные</param>
/// <returns>Данные</returns>
T? Deserialize<T> (string json);
}

View File

@ -1,22 +0,0 @@
namespace anbs_cp.Interfaces;
/// <summary>
/// Интерфейс конвертера величин для отображения (улучшенный аналог IValueFormatter)
/// </summary>
public interface IValueConverter
{
/// <summary>
/// Массив имён размерностей
/// </summary>
public string[] ValueNames { get; init; }
/// <summary>
/// Делитель
/// </summary>
public long Divider { get; init; }
/// <summary>
/// Знаков после запятой (0, 1, 2)
/// </summary>
public byte DecimalPlaces { get; init; }
}

View File

@ -1,75 +0,0 @@
namespace anbs_cp.Interfaces;
/// <summary>
/// Форматирует размерности в понятную строку
/// </summary>
public interface IValueFormatter
{
#region Определения интерфейса
/// <summary>
/// Имена размерностей
/// </summary>
public string[] ValueNames { get; set; }
/// <summary>
/// Знаков после запятой
/// </summary>
public byte DecimalPlaces { get; set; }
/// <summary>
/// Максимальные размеры (массив ulong[4])
/// </summary>
public long[] MaxSizes { get; set; }
#endregion
#region Методы интерфейса
/// <summary>
/// Форматирование размерности
/// </summary>
/// <param name="value">Размерность, требующая форматирования</param>
/// <returns>Форматированная размерность (например, 20 Мб)</returns>
public string Format(long value)
{
//Левая граница
long leftnum;
//Правая граница
long rightnum;
for (int i = 0; i <= MaxSizes.Length; i++)
{
leftnum = i == 0 ? 0 : MaxSizes[i - 1];
rightnum = i == MaxSizes.Length ? long.MaxValue : MaxSizes[i];
if (value >= leftnum && value < rightnum)
return $"{FormatValue(value, leftnum)} {ValueNames[i]}";
}
return value.ToString();
}
/// <summary>
/// Деление числа на число с DecimalPlaces знаками после запятой
/// </summary>
/// <param name="dividend">Делимое число</param>
/// <param name="divider">Число-делитель</param>
/// <returns>Частное (с DecimalPlaces знаками после запятой)</returns>
private string FormatValue(long dividend, long divider)
{
if (divider == 0) return $"{dividend}";
long delim = 1;
for (int i = 0; i <= DecimalPlaces; i++) delim *= 10;
// ReSharper disable once PossibleLossOfFraction
decimal value = Math.Round((decimal)(dividend * delim / divider)) / delim;
return $"{value}";
}
#endregion
}

48
anbs_cp/LikeDelphi.cs Normal file
View File

@ -0,0 +1,48 @@
using System.Collections.Generic;
namespace anbs_cp
{
/// <summary>
/// Класс, добавляющий реализацию некоторых методов Delphi, которые упрощают работу в C#.
/// </summary>
public static class LikeDelphi
{
/// <summary>
/// Аналог функции IncludeTrailingBackslash
/// </summary>
/// <param name="path">Путь, к которому нужно добавить slash</param>
/// <returns>Путь со slash в конце</returns>
public static string IncludeTrailingBackslash(string path)
{
string result = path;
int Index = path.Length - 1;
if (path[Index] != '\\')
{
result = $"{path}\\";
}
return result;
}
/// <summary>
/// Парсер строки в множество строк
/// </summary>
/// <param name="astring">Строка, которую нужно разбить</param>
/// <param name="delim">Символ-делитель строки</param>
/// <returns>Массив строк</returns>
public static List<string> ParseString(string astring, char delim)
{
int from = -1;
int to;
List<string> result = new();
do
{
from++;
to = astring.IndexOf(delim, from);
if (to <= 0)
to = astring.Length;
if (from != to)
result.Add(astring[from..(to-from)]);
from = to;
} while (to != astring.Length);
return result;
}
}
}

View File

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

View File

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

View File

@ -1,110 +0,0 @@
using anbs_cp.Classes;
using anbs_cp.Interfaces;
namespace anbs_cp.Structs;
/// <summary>
/// Двумерный размер
/// </summary>
/// <param name="width">Длина</param>
/// <param name="height">Высота</param>
public struct TwoDimSize (int width = 0, int height = 0): ISerializable
{
#region Приватные поля
/// <summary>
/// Длина (приватное)
/// </summary>
private int _pWidth = width;
/// <summary>
/// Ширина (приватное)
/// </summary>
private int _pHeight = height;
#endregion
#region Свойства
/// <summary>
/// Длина
/// </summary>
public int Width
{
readonly get => _pWidth;
set => _pWidth = value < 0 ? 0 : value;
}
/// <summary>
/// Ширина
/// </summary>
public int Height
{
readonly get => _pHeight;
set => _pHeight = value < 0 ? 0 : value;
}
#endregion
#region Методы
/// <summary>
/// Конвертация в строку
/// </summary>
/// <param name="delimiter">Делитель размера</param>
/// <returns>Строка</returns>
public readonly string ToString (char delimiter = ':') => $"{_pWidth}{delimiter}{_pHeight}";
/// <summary>
/// Получение размера из строки
/// </summary>
/// <param name="s">Строка</param>
/// <param name="delimiter">Разделитель размеров</param>
/// <returns>Модель размеров</returns>
/// <exception cref="ArgumentOutOfRangeException">Если в строке <paramref name="s"/> не содержится символа
/// <paramref name="delimiter"/> или таких разделителей слишком много</exception>
public static TwoDimSize Parse (string s, char delimiter = ':')
{
// Разделяю значения
string[] splitSizes = s.Split(delimiter);
// Проверяю, что массив имеет ровно два элемента
if (splitSizes.Length != 2)
throw new ArgumentOutOfRangeException(delimiter.ToString(),
$"Похоже, что в строке {s} не содержится символа {delimiter} или таких разделителей слишком много!");
// Пытаюсь получить длину
if (!int.TryParse(splitSizes[0], out int width))
width = 0;
// Пытаюсь получить ширину
if (!int.TryParse(splitSizes[1], out int height))
height = 0;
// Вывожу значение
return new(width, height);
}
#endregion
#region Реализация интерфейса ISerializable
/// <summary>
/// Сериализовать элемент в формат json
/// </summary>
/// <returns>Строка в формате json</returns>
public readonly string Serialize () => new SysTextSerializer().Serialize(ToString());
/// <summary>
/// Восстановить элемент из формата json
/// </summary>
/// <param name="json">Строка в формате json</param>
public void Deserialize (string json)
{
// Десериализую строку
string deserialized = new SysTextSerializer().Deserialize<string>(json) ?? "0:0";
// Перевожу строку в двумерный размер
TwoDimSize result = Parse(deserialized);
// Присваиваю длину
_pWidth = result.Width;
// Присваиваю ширину
_pHeight = result.Height;
}
#endregion
}

114
anbs_cp/TypeConverter.cs Normal file
View File

@ -0,0 +1,114 @@
namespace anbs_cp
{
/// <summary>
/// Конвертер типов на манер Delphi
/// </summary>
public static class TypeConverter
{
#region Конвертация числа в строку
/// <summary>
/// Преобразование int в string
/// </summary>
/// <param name="AInt">Число</param>
/// <returns>Строка</returns>
public static string IntToStr(int AInt) => AInt.ToString();
/// <summary>
/// Преобразование uint в string
/// </summary>
/// <param name="AInt">Число</param>
/// <returns>Строка</returns>
public static string IntToStr(uint AInt) => AInt.ToString();
/// <summary>
/// Преобразование long в string
/// </summary>
/// <param name="AInt">Число</param>
/// <returns>Строка</returns>
public static string IntToStr(long AInt) => AInt.ToString();
/// <summary>
/// Преобразование ulong в string
/// </summary>
/// <param name="AInt">Число</param>
/// <returns>Строка</returns>
public static string IntToStr(ulong AInt) => AInt.ToString();
/// <summary>
/// Преобразование byte в string
/// </summary>
/// <param name="AInt">Число</param>
/// <returns>Строка</returns>
public static string IntToStr(byte AInt) => AInt.ToString();
#endregion
#region Конвертация строки в число
/// <summary>
/// Преобразование строки в число
/// </summary>
/// <param name="AStr">Строка</param>
/// <param name="ADefault">Значение по умолчанию (по умолчанию, 0)</param>
/// <returns>Число</returns>
public static int StrToInt(string AStr, int ADefault = 0)
{
if (!int.TryParse(AStr, out int result))
{
result = ADefault;
}
return result;
}
/// <summary>
/// Преобразование строки в число
/// </summary>
/// <param name="AStr">Строка</param>
/// <param name="ADefault">Значение по умолчанию (по умолчанию, 0)</param>
/// <returns>Число</returns>
public static uint StrToUInt(string AStr, uint ADefault = 0)
{
if (!uint.TryParse(AStr, out uint result))
{
result = ADefault;
}
return result;
}
/// <summary>
/// Преобразование строки в число
/// </summary>
/// <param name="AStr">Строка</param>
/// <param name="ADefault">Значение по умолчанию (по умолчанию, 0)</param>
/// <returns>Число</returns>
public static long StrToInt64(string AStr, long ADefault = 0)
{
if (!long.TryParse(AStr, out long result))
{
result = ADefault;
}
return result;
}
/// <summary>
/// Преобразование строки в число
/// </summary>
/// <param name="AStr">Строка</param>
/// <param name="ADefault">Значение по умолчанию (по умолчанию, 0)</param>
/// <returns>Число</returns>
public static ulong StrToUInt64(string AStr, ulong ADefault = 0)
{
if (!ulong.TryParse(AStr, out ulong result))
{
result = ADefault;
}
return result;
}
/// <summary>
/// Преобразование строки в число
/// </summary>
/// <param name="AStr">Строка</param>
/// <param name="ADefault">Значение по умолчанию (по умолчанию, 0)</param>
/// <returns>Число</returns>
public static byte StrToByte(string AStr, byte ADefault = 0)
{
if (!byte.TryParse(AStr, out byte result))
{
result = ADefault;
}
return result;
}
#endregion
}
}

View File

@ -1,48 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>2024.8.18</Version>
<Authors>Александр Бабаев</Authors>
<Product>Набор компонентов ANB Software</Product>
<Description>Библиотека полезных методов языка C#</Description>
<Copyright>Александр Бабаев</Copyright>
<TargetFramework>net6.0</TargetFramework>
<Version>1.20211111.0</Version>
<Authors>Alexander Babaev</Authors>
<Product>ANB Software Components Pack</Product>
<Description>Library of some useful functions in C# language.</Description>
<Copyright>Alexander Babaev</Copyright>
<AssemblyName>anbs_cp</AssemblyName>
<RootNamespace>anbs_cp</RootNamespace>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<SignAssembly>True</SignAssembly>
<PackageProjectUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</PackageProjectUrl>
<RepositoryUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</RepositoryUrl>
<AssemblyVersion></AssemblyVersion>
<FileVersion></FileVersion>
<PackageId>ANBSoftware.ComponentsPack</PackageId>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<AnalysisLevel>6.0</AnalysisLevel>
<RepositoryType>git</RepositoryType>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>Библиотека полезных методов и классов от ANB</Title>
<SignAssembly>False</SignAssembly>
<PackageProjectUrl>https://github.com/GoodBoyAlex/anbsoftware_componentspack</PackageProjectUrl>
<RepositoryUrl>https://github.com/GoodBoyAlex/anbsoftware_componentspack</RepositoryUrl>
<AssemblyVersion>1.2021.1111</AssemblyVersion>
<FileVersion>1.2021.1111</FileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<WarningLevel>7</WarningLevel>
<WarningLevel>2</WarningLevel>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<WarningLevel>7</WarningLevel>
<WarningLevel>2</WarningLevel>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DebugType>none</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MimeTypes" Version="2.5.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop" Version="17.0.31902.203" />
</ItemGroup>
</Project>

View File

@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp120</s:String></wpf:ResourceDictionary>

View File

@ -1,367 +0,0 @@
using anbs_cp.Database.Interfaces;
using Dapper;
using MySqlConnector;
namespace anbs_cp.Database.Classes;
/// <summary>
/// База данных MySQL
/// </summary>
/// <param name="connectionString">Строка подключения базы данных</param>
public class MySqlEngine (string connectionString): IDbEngine
{
/// <summary>
/// Строка подключения базы данных
/// </summary>
public string ConnectionString { get; set; } = connectionString;
#region Базовые операции
/// <summary>
/// Выполняем команду
/// </summary>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Количество затронутых строк</returns>
public async Task<int> ExecuteAsync (string sql, object? values = null)
{
// Подключаемся к БД
await using MySqlConnection connection = new(ConnectionString);
// Открываем соединение
await connection.OpenAsync();
// Выполняем команду и выводим результат
return await connection.ExecuteAsync(sql, values);
}
/// <summary>
/// Выполняем команду
/// </summary>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Количество затронутых строк</returns>
public int Execute (string sql, object? values = null) => ExecuteAsync(sql, values).GetAwaiter().GetResult();
/// <summary>
/// Запрос
/// </summary>
/// <typeparam name="T">Тип передаваемого значения</typeparam>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Возвращает массив типа <see cref="T"/> или значение по умолчанию</returns>
public async Task<IEnumerable<T>> QueryAsync<T> (string sql, object? values = null)
{
// Подключаемся к БД
await using MySqlConnection connection = new(ConnectionString);
// Открываем соединение
await connection.OpenAsync();
// Выполняем запрос и выводим результат
return await connection.QueryAsync<T>(sql, values);
}
/// <summary>
/// Запрос
/// </summary>
/// <typeparam name="T">Тип передаваемого значения</typeparam>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Возвращает массив типа <see cref="T"/> или значение по умолчанию</returns>
public IEnumerable<T> Query<T> (string sql, object? values = null) => QueryAsync<T>(sql, values).GetAwaiter().GetResult();
/// <summary>
/// Запрос строки
/// </summary>
/// <typeparam name="T">Тип передаваемого значения</typeparam>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Возвращает массив типа <see cref="T"/> или значение по умолчанию</returns>
public async Task<T?> QueryRowAsync<T> (string sql, object? values = null)
{
// Подключаемся к БД
await using MySqlConnection connection = new(ConnectionString);
// Открываем соединение
await connection.OpenAsync();
// Выполняем запрос и выводим результат
return await connection.QuerySingleOrDefaultAsync<T>(sql, values);
}
/// <summary>
/// Запрос строки
/// </summary>
/// <typeparam name="T">Тип передаваемого значения</typeparam>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Возвращает массив типа <see cref="T"/> или значение по умолчанию</returns>
public T? QueryRow<T> (string sql, object? values = null) => QueryRowAsync<T>(sql, values).GetAwaiter().GetResult();
#endregion
#region Получение данных
/// <summary>
/// Получает массив данных (SELECT * FROM...)
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Массив результата запроса</returns>
public async Task<IEnumerable<T>> GetResultsAsync<T> (string sql, object? values = null) => await QueryAsync<T>(sql, values);
/// <summary>
/// Получает массив данных (SELECT * FROM...)
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Массив результата запроса</returns>
public IEnumerable<T> GetResults<T> (string sql, object? values = null) => GetResultsAsync<T>(sql, values).GetAwaiter().GetResult();
/// <summary>
/// Получает строку в массиве данных
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Строки данных или null</returns>
public async Task<T?> GetRowAsync<T> (string sql, object? values = null)
{
// Подключаемся к БД
await using MySqlConnection connection = new(ConnectionString);
// Открываем соединение
await connection.OpenAsync();
// Выполняем запрос и выводим результат
return await connection.QuerySingleOrDefaultAsync<T>(sql, values);
}
/// <summary>
/// Получает строку в массиве данных
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Строки данных или null</returns>
public T? GetRow<T> (string sql, object? values = null) => GetRowAsync<T>(sql, values).GetAwaiter().GetResult();
/// <summary>
/// Получает колонку в массиве данных
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Колонка данных или null</returns>
public async Task<IEnumerable<T>> GetColAsync<T> (string sql, object? values = null)
where T : IComparable, IConvertible, IEquatable<T> => await QueryAsync<T>(sql, values);
/// <summary>
/// Получает колонку в массиве данных
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Колонка данных или null</returns>
public IEnumerable<T> GetCol<T> (string sql, object? values = null) where T : IComparable, IConvertible, IEquatable<T> =>
GetColAsync<T>(sql, values).GetAwaiter().GetResult();
/// <summary>
/// Получение значение единичного поля
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Поле или null</returns>
public async Task<T?> GetVarAsync<T> (string sql, object? values = null) where T : IComparable, IConvertible, IEquatable<T>
{
// Подключаемся к БД
await using MySqlConnection connection = new(ConnectionString);
// Открываем соединение
await connection.OpenAsync();
// Выполняем запрос и выводим результат
return await connection.QuerySingleOrDefaultAsync<T>(sql, values);
}
/// <summary>
/// Получение значение единичного поля
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Поле или null</returns>
public T? GetVar<T> (string sql, object? values = null) where T : IComparable, IConvertible, IEquatable<T> =>
GetVarAsync<T>(sql, values).GetAwaiter().GetResult();
#endregion
#region CRUD данные
/// <summary>
/// Вставляет данные в таблицу
/// </summary>
/// <typeparam name="T">Класс данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <returns>Результат выполнения</returns>
public async Task<bool> InsertAsync<T> (T data, string tableName) where T : class
{
// Получение список имён свойств в data
List<string> propertyNamesList = (from dataProperty in data.GetType().GetProperties() select dataProperty.Name).ToList();
// Получаем список имён в data, обрамленные @
List<string> propertyValuesList = propertyNamesList.Select(static propertyName => $"@{propertyName}").ToList();
//Получаем строку имён свойств
string propertyNames = string.Join(", ", propertyNamesList.ToArray());
// Получаем строку имён свойств, обрамленных @
string propertyValues = string.Join(", ", propertyValuesList.ToArray());
// Создаю соединение
await using MySqlConnection connection = new(ConnectionString);
// Создаю запрос
string sql = $"""
INSERT
INTO {tableName} ({propertyNames})
VALUES ({propertyValues})
""";
// Выполняю запрос
return await connection.ExecuteAsync(sql, data) > 0;
}
/// <summary>
/// Вставляет данные в таблицу
/// </summary>
/// <typeparam name="T">Класс данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <returns>Результат выполнения</returns>
public bool Insert<T> (T data, string tableName) where T : class => InsertAsync(data, tableName).GetAwaiter().GetResult();
/// <summary>
/// Обновляет строку в таблице
/// </summary>
/// <typeparam name="T">Класс данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
public async Task<bool> UpdateAsync<T> (T data, string tableName, string whereConditionColumn) where T : class
{
// Получение список имён свойств в data
List<string> propertyNamesList = (from dataProperty in data.GetType().GetProperties()
where dataProperty.Name != whereConditionColumn
select dataProperty.Name).ToList();
// Получаем список имён в data, обрамленные @
List<string> propertyKeyValuesList = propertyNamesList.Select(static propertyName => $"{propertyName}=@{propertyName}").ToList();
// Получаем строку имён свойств, обрамленных @
string properties = string.Join(", ", propertyKeyValuesList.ToArray());
// Создаю соединение
await using MySqlConnection connection = new(ConnectionString);
// Создаю запрос
string sql = $"""
UPDATE {tableName}
SET
{properties}
WHERE
{whereConditionColumn}=@{whereConditionColumn}
""";
// Выполняю запрос
return await connection.ExecuteAsync(sql, data) > 0;
}
/// <summary>
/// Обновляет строку в таблице
/// </summary>
/// <typeparam name="T">Класс данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
public bool Update<T> (T data, string tableName, string whereConditionColumn) where T : class =>
UpdateAsync(data, tableName, whereConditionColumn).GetAwaiter().GetResult();
/// <summary>
/// Удаляет строки
/// </summary>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
public async Task<bool> DeleteAsync<T> (T data, string tableName, string whereConditionColumn) where T : class
{
// Создаю соединение
await using MySqlConnection connection = new(ConnectionString);
// Создаю запрос
string sql = $"""
DELETE FROM
{tableName}
WHERE
{whereConditionColumn}=@{whereConditionColumn}
""";
// Выполняю запрос
return await connection.ExecuteAsync(sql, data) > 0;
}
/// <summary>
/// Удаляет строки
/// </summary>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
public bool Delete<T> (T data, string tableName, string whereConditionColumn) where T : class =>
DeleteAsync(data, tableName, whereConditionColumn).GetAwaiter().GetResult();
/// <summary>
/// Удаляет строку
/// </summary>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
public async Task<bool> DeleteRowAsync<T> (T data, string tableName, string whereConditionColumn) where T : class
{
// Создаю соединение
await using MySqlConnection connection = new(ConnectionString);
// Создаю запрос
string sql = $"""
DELETE FROM
{tableName}
WHERE
{whereConditionColumn}=@{whereConditionColumn}
LIMIT 1
""";
// Выполняю запрос
return await connection.ExecuteAsync(sql, data) > 0;
}
/// <summary>
/// Удаляет строку
/// </summary>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
public bool DeleteRow<T> (T data, string tableName, string whereConditionColumn) where T : class =>
DeleteRowAsync(data, tableName, whereConditionColumn).GetAwaiter().GetResult();
#endregion
}

View File

@ -1,219 +0,0 @@
namespace anbs_cp.Database.Interfaces;
/// <summary>
/// Интерфейс для работы с базой данных
/// </summary>
public interface IDbEngine
{
/// <summary>
/// Строка подключения
/// </summary>
string ConnectionString { get; set; }
#region Базовые операции
/// <summary>
/// Выполняем команду
/// </summary>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Количество затронутых строк</returns>
Task<int> ExecuteAsync (string sql, object? values = null);
/// <summary>
/// Выполняем команду
/// </summary>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Количество затронутых строк</returns>
int Execute (string sql, object? values = null);
/// <summary>
/// Запрос
/// </summary>
/// <typeparam name="T">Тип передаваемого значения</typeparam>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Возвращает массив типа <see cref="T"/> или значение по умолчанию</returns>
Task<IEnumerable<T>> QueryAsync<T> (string sql, object? values = null);
/// <summary>
/// Запрос
/// </summary>
/// <typeparam name="T">Тип передаваемого значения</typeparam>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Возвращает массив типа <see cref="T"/> или значение по умолчанию</returns>
IEnumerable<T> Query<T> (string sql, object? values = null);
/// <summary>
/// Запрос строки
/// </summary>
/// <typeparam name="T">Тип передаваемого значения</typeparam>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Возвращает массив типа <see cref="T"/> или значение по умолчанию</returns>
Task<T?> QueryRowAsync<T> (string sql, object? values = null);
/// <summary>
/// Запрос строки
/// </summary>
/// <typeparam name="T">Тип передаваемого значения</typeparam>
/// <param name="sql">Запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Возвращает массив типа <see cref="T"/> или значение по умолчанию</returns>
T? QueryRow<T> (string sql, object? values = null);
#endregion
#region Получение данных
/// <summary>
/// Получает массив данных (SELECT * FROM...)
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Массив результата запроса</returns>
Task<IEnumerable<T>> GetResultsAsync<T> (string sql, object? values = null);
/// <summary>
/// Получает массив данных (SELECT * FROM...)
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Массив результата запроса</returns>
IEnumerable<T> GetResults<T> (string sql, object? values = null);
/// <summary>
/// Получает строку в массиве данных
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Строки данных или null</returns>
Task<T?> GetRowAsync<T> (string sql, object? values = null);
/// <summary>
/// Получает строку в массиве данных
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Строки данных или null</returns>
T? GetRow<T> (string sql, object? values = null);
/// <summary>
/// Получает колонку в массиве данных
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Колонка данных или null</returns>
Task<IEnumerable<T>> GetColAsync<T> (string sql, object? values = null) where T: IComparable, IConvertible, IEquatable<T>;
/// <summary>
/// Получает колонку в массиве данных
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Колонка данных или null</returns>
IEnumerable<T> GetCol<T> (string sql, object? values = null) where T: IComparable, IConvertible, IEquatable<T>;
/// <summary>
/// Получение значение единичного поля
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Поле или null</returns>
Task<T?> GetVarAsync<T> (string sql, object? values = null) where T: IComparable, IConvertible, IEquatable<T>;
/// <summary>
/// Получение значение единичного поля
/// </summary>
/// <typeparam name="T">Тип получаемых данных</typeparam>
/// <param name="sql">SQL-запрос</param>
/// <param name="values">Данные запроса</param>
/// <returns>Поле или null</returns>
T? GetVar<T> (string sql, object? values = null) where T: IComparable, IConvertible, IEquatable<T>;
#endregion
#region CRUD данные
/// <summary>
/// Вставляет данные в таблицу
/// </summary>
/// <typeparam name="T">Класс данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <returns>Результат выполнения</returns>
Task<bool> InsertAsync<T> (T data, string tableName) where T: class;
/// <summary>
/// Вставляет данные в таблицу
/// </summary>
/// <typeparam name="T">Класс данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <returns>Результат выполнения</returns>
bool Insert<T> (T data, string tableName) where T: class;
/// <summary>
/// Обновляет строку в таблице
/// </summary>
/// <typeparam name="T">Класс данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
Task<bool> UpdateAsync<T> (T data, string tableName, string whereConditionColumn) where T: class;
/// <summary>
/// Обновляет строку в таблице
/// </summary>
/// <typeparam name="T">Класс данных</typeparam>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
bool Update<T> (T data, string tableName, string whereConditionColumn) where T: class;
/// <summary>
/// Удаляет строки
/// </summary>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
Task<bool> DeleteAsync<T> (T data, string tableName, string whereConditionColumn) where T: class;
/// <summary>
/// Удаляет строки
/// </summary>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
bool Delete<T> (T data, string tableName, string whereConditionColumn) where T: class;
/// <summary>
/// Удаляет строку
/// </summary>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
Task<bool> DeleteRowAsync <T> (T data, string tableName, string whereConditionColumn) where T: class;
/// <summary>
/// Удаляет строку
/// </summary>
/// <param name="data">Данные</param>
/// <param name="tableName">Имя таблицы</param>
/// <param name="whereConditionColumn">Условие поиска строки. ВНИМАНИЕ! Должно быть одним из указанных свойств типа класса data</param>
/// <returns>Результат выполнения</returns>
bool DeleteRow <T> (T data, string tableName, string whereConditionColumn) where T: class;
#endregion
}

View File

@ -1,27 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyName>anbs_cp_db</AssemblyName>
<RootNamespace>anbs_cp.Database</RootNamespace>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageId>ANBSoftware.ComponentsPack.Database</PackageId>
<Version>2024.4.26</Version>
<Company>Александр Бабаев</Company>
<Product>Набор компонентов ANB Software для работы с БД</Product>
<Description>Библиотека полезных методов языка C# для работы с базами данных</Description>
<Copyright>Александр Бабаев</Copyright>
<PackageProjectUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</PackageProjectUrl>
<RepositoryUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Authors>Александр Бабаев</Authors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="MySqlConnector" Version="2.3.7" />
</ItemGroup>
</Project>

View File

@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp120</s:String></wpf:ResourceDictionary>

View File

@ -1,23 +0,0 @@
using Microsoft.Extensions.Configuration;
namespace anbs_cp.ForNet.Classes;
/// <summary>
/// Класс-поддержки для доступа к файлу "appsettings.json" в любом месте сайта классах.
/// Взято с: https://stackoverflow.com/a/69111159/16469671
/// </summary>
public static class AppSettings
{
// ReSharper disable once NotAccessedField.Global
// ReSharper disable once NotNullOrRequiredMemberIsNotInitialized
public static IConfiguration? Config { get; private set; }
/// <summary>
/// Инициализация настроек. Она проводится в файле Program.cs.
/// </summary>
/// <param name="configuration">Параметры из "appsettings.json"</param>
public static void Initialize (IConfiguration configuration)
{
Config = configuration;
}
}

View File

@ -1,118 +0,0 @@
using System.ComponentModel.DataAnnotations;
using anbs_cp.Classes;
using anbs_cp.ForNet.Constants;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
namespace anbs_cp.ForNet.Classes;
/// <summary>
/// Кастомные сообщения валидации формы
/// </summary>
/// <param name="messageList">Кастомный список сообщений формы</param>
public class CustomValidationMessages (KeyValueOrderedList<string>? messageList): IValidationMetadataProvider
{
/// <summary>
/// Список сообщений формы
/// </summary>
// ReSharper disable once MemberCanBePrivate.Global
public readonly KeyValueOrderedList<string> MessageList = messageList ?? ValidationMessagesConstants.English;
/// <summary>
/// Создаёт данные для локализации сообщений валидации
/// </summary>
/// <param name="context">Контекст</param>
public void CreateValidationMetadata (ValidationMetadataProviderContext context)
{
// Если context = null, то прерываем с ошибкой
ArgumentNullException.ThrowIfNull(context);
// Получаю мета-данные
IList<object>? 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<RequiredAttribute>(attribute);
// MinLengthAttribute
FillErrorMessage<MinLengthAttribute>(attribute);
// MaxLengthAttribute
FillErrorMessage<MaxLengthAttribute>(attribute);
// EmailAddressAttribute
FillErrorMessage<EmailAddressAttribute>(attribute);
// RangeAttribute
FillErrorMessage<RangeAttribute>(attribute);
// CompareAttribute
FillErrorMessage<CompareAttribute>(attribute);
// RegularExpressionAttribute
FillErrorMessage<RegularExpressionAttribute>(attribute);
// PhoneAttribute
FillErrorMessage<PhoneAttribute>(attribute);
// CreditCardAttribute
FillErrorMessage<CreditCardAttribute>(attribute);
}
}
/// <summary>
/// Устанавливает сообщение об ошибке валидации
/// </summary>
/// <typeparam name="T">Тип атрибута валидации</typeparam>
/// <param name="attribute">Атрибут</param>
private void FillErrorMessage<T> (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;
}
}
}

View File

@ -1,17 +0,0 @@
using Microsoft.AspNetCore.Http;
namespace anbs_cp.ForNet.Classes;
/// <summary>
/// Класс -- расширение для класса File
/// </summary>
public class NetFileExtension
{
/// <summary>
/// Получает MIME-тип файла
/// </summary>
/// <param name="file">Загружаемый файл</param>
/// <returns>MIME-тип файла</returns>
public static string MimeType (IFormFile file) =>
file.ContentType;
}

View File

@ -1,38 +0,0 @@
using System.Security.Cryptography;
using anbs_cp.Classes;
using Microsoft.AspNetCore.Http;
namespace anbs_cp.ForNet.Classes;
public static class NetFileHash
{
/// <summary>
/// Получение md5-хэша загружаемого файла.
/// Взято с https://stackoverflow.com/a/67081012/16469671
/// </summary>
/// <param name="file">Загружаемый файл</param>
/// <returns>Массив хэша</returns>
public static FileHash GetFileHash (IFormFile file)
{
//Создаю md5
using MD5 md5 = MD5.Create();
//Создаю поток для чтения
using StreamReader streamReader = new(file.OpenReadStream());
//Получаю строковый хэш
string hash = BitConverter.ToString(md5.ComputeHash(streamReader.BaseStream)).Replace("-", "")
.ToLowerInvariant();
//Создаю результат
FileHash fileHash = new();
//Вношу в него данные
fileHash.FromString(hash);
//Возвращаю результат
return fileHash;
}
}

View File

@ -1,35 +0,0 @@
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Html;
namespace anbs_cp.ForNet.Classes;
/// <summary>
/// Расширение конвертера типов на манер Delphi
/// </summary>
public static class NetTypeConverter
{
#region Конвернтация IHtmlContent
/// <summary>
/// Преобразует тип <see cref="IHtmlContent"/> в строку <see cref="string"/>.
/// </summary>
/// <param name="content">Значение, которое нужно преобразовать.</param>
/// <returns><see cref="string"/></returns>
public static string HtmlContentToString(IHtmlContent content)
{
//Создаём writer
using StringWriter writer = new();
//Конвертируем IHtmlContent в string
content.WriteTo(writer, HtmlEncoder.Default);
//Возвращаем результат
return writer.ToString();
}
/// <summary>
/// Преобразует строку <see cref="string"/> в тип <see cref="IHtmlContent"/>.
/// </summary>
/// <param name="content">Значение, которое нужно преобразовать.</param>
/// <returns><see cref="IHtmlContent"/></returns>
public static IHtmlContent StringToHtmlContent(string content) => new HtmlContentBuilder().AppendHtml(content);
#endregion
}

View File

@ -1,70 +0,0 @@
using System.Text;
using anbs_cp.Interfaces;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
namespace anbs_cp.ForNet.Classes;
/// <summary>
/// Класс шифрования пароля
/// </summary>
public sealed class PasswordEncrypt: IEncryptor
{
/// <summary>
/// Шифрование пароля
/// </summary>
/// <param name="password">Пароль</param>
/// <param name="salt">Хэш-код пароля</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>Зашифрованный пароль</returns>
public string Encrypt (string password, string salt, string valueIfFail)
{
try
{
// Получаю byte-массив из хэш-кода пароля
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
// Шифрую пароль
byte[] encryptedPassword = KeyDerivation.Pbkdf2(password, saltBytes, KeyDerivationPrf.HMACSHA512, 5000, 64);
// Возвращаю зашифрованный пароль
return Convert.ToBase64String(encryptedPassword);
}
catch (FormatException)
{
return valueIfFail;
}
}
/// <summary>
/// Этот метод не требует реализации в этом классе!
/// </summary>
/// <param name="encryptedValue">НЕ РАБОТАЕТ</param>
/// <param name="salt">НЕ РАБОТАЕТ</param>
/// <returns>НЕ РАБОТАЕТ</returns>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <exception cref="NotImplementedException">Этот метод не требует реализации в этом классе!</exception>
public string Decrypt (string encryptedValue, string salt, string valueIfFail) =>
throw new NotImplementedException("Этот метод не требует реализации в этом классе!");
/// <summary>
/// Этот метод не требует реализации в этом классе!
/// </summary>
/// <param name="text">НЕ РАБОТАЕТ</param>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <returns>НЕ РАБОТАЕТ</returns>
/// <exception cref="NotImplementedException">Этот метод не требует реализации в этом классе!</exception>
public string Base64UrlEncode (string text, string valueIfFail) =>
throw new NotImplementedException("Этот метод не требует реализации в этом классе!");
/// <summary>
/// Этот метод не требует реализации в этом классе!
/// </summary>
/// <param name="text">НЕ РАБОТАЕТ</param>
/// <returns>НЕ РАБОТАЕТ</returns>
/// <param name="valueIfFail">Значение, если неудача</param>
/// <exception cref="NotImplementedException">Этот метод не требует реализации в этом классе!</exception>
public string Base64UrlDecode (string text, string valueIfFail) =>
throw new NotImplementedException("Этот метод не требует реализации в этом классе!");
}

View File

@ -1,208 +0,0 @@
using anbs_cp.ForNet.Enums;
using Ganss.Xss;
namespace anbs_cp.ForNet.Classes;
/// <summary>
/// Очистка текста от лишних HTML-тегов
/// </summary>
public static class Sanitizer
{
#region Свойства
/// <summary>
/// Все теги запрещены
/// </summary>
public static SanitizerAllowedHtml AllowedNone => GetNone();
/// <summary>
/// Все теги разрешены
/// </summary>
public static SanitizerAllowedHtml AllowedAll => GetAll();
/// <summary>
/// Оставлены только текстовые теги
/// </summary>
public static SanitizerAllowedHtml AllowedTextOnly => GetTextFormatOnly();
/// <summary>
/// Оставлены только текстовые теги, а также img и a
/// </summary>
public static SanitizerAllowedHtml AllowedImageAndLinks => GetImageAndLinks();
/// <summary>
/// Применяются все теги, кроме iframe
/// </summary>
public static SanitizerAllowedHtml AllowedAllExceptIFrame => GetAllExceptIFrame();
#endregion
#region Методы
/// <summary>
/// Очистка html-кода <paramref name="html" /> согласно параметрам <paramref name="allowedHtml" />
/// </summary>
/// <param name="html">HTML-код</param>
/// <param name="allowedHtml">Параметры очистки</param>
/// <returns>Очищенный html-кода</returns>
public static string SanitizeHtml (string html, SanitizerAllowedHtml allowedHtml)
{
// Создаю очиститель
HtmlSanitizer sanitizer = new()
{
// - сохраняю дочерние удалённых
KeepChildNodes = true
};
// Выключаю все параметры HTML
sanitizer.AllowedTags.Clear();
sanitizer.AllowedSchemes.Clear();
sanitizer.AllowedCssProperties.Clear();
sanitizer.AllowedClasses.Clear();
sanitizer.AllowedAttributes.Clear();
sanitizer.AllowedAtRules.Clear();
sanitizer.AllowDataAttributes = false;
// Загружаю параметры
sanitizer.AllowedTags.UnionWith(allowedHtml.AllowedTags);
sanitizer.AllowedSchemes.UnionWith(allowedHtml.AllowedSchemes);
sanitizer.AllowedCssProperties.UnionWith(allowedHtml.AllowedCssProperties);
sanitizer.AllowedClasses.UnionWith(allowedHtml.AllowedClasses);
sanitizer.AllowedAttributes.UnionWith(allowedHtml.AllowedAttributes);
sanitizer.AllowDataAttributes = allowedHtml.AllowDataAttributes;
// Очищаю html согласно правилам
return sanitizer.Sanitize(html);
}
/// <summary>
/// Очистка html-кода по уровню очистки
/// </summary>
/// <param name="html">HTML-код</param>
/// <param name="level">Уровень очистка</param>
/// <returns>Очищенный html-код</returns>
public static string SanitizeHtml (string html, ESanitizerLevel level)
{
// Получаю параметры очистки
SanitizerAllowedHtml allowedHtml = level switch
{
ESanitizerLevel.NoTags => AllowedNone,
ESanitizerLevel.TextFormatOnly => AllowedTextOnly,
ESanitizerLevel.ImageAndLinks => AllowedImageAndLinks,
ESanitizerLevel.AllExceptIFrame => AllowedAllExceptIFrame,
ESanitizerLevel.All => AllowedAll,
var _ => AllowedAll
};
// Очищаю код и возвращаю результат очистки
return SanitizeHtml(html, allowedHtml);
}
#endregion
#region Вспомогателдьные методы
/// <summary>
/// Получаю параметры, удаляющие все теги
/// </summary>
/// <returns>Параметры очистки</returns>
private static SanitizerAllowedHtml GetNone () =>
new()
{
AllowedTags = [],
AllowedAttributes = [],
AllowedCssProperties = [],
AllowedClasses = [],
AllowedSchemes = [],
AllowDataAttributes = false
};
/// <summary>
/// Получаю параметры по умолчанию (разрешающие все теги)
/// </summary>
/// <returns>Параметры очистки</returns>
private static SanitizerAllowedHtml GetAll ()
{
// Создаю очиститель
HtmlSanitizer sanitizer = new();
// Создаю модель
return new()
{
AllowedTags = sanitizer.AllowedTags.ToList(),
AllowedAttributes = sanitizer.AllowedAttributes.ToList(),
AllowedCssProperties = sanitizer.AllowedCssProperties.ToList(),
AllowedClasses = sanitizer.AllowedClasses.ToList(),
AllowedSchemes = sanitizer.AllowedSchemes.ToList(),
AllowDataAttributes = true
};
}
/// <summary>
/// Параметры, оставляющие только текстовые теги
/// </summary>
/// <returns>Параметры очистки</returns>
private static SanitizerAllowedHtml GetTextFormatOnly () =>
new()
{
AllowedTags =
[
"strong", "b", "em", "i", "u", "hr", "strike", "div", "ol", "ul", "li", "p", "span", "h1", "h2", "h3",
"h4"
],
// ReSharper disable StringLiteralTypo
AllowedAttributes =
[
"align", "bgcolor", "border", "cellpadding", "cellspacing", "charset", "checked", "class", "clear",
"color",
"cols", "colspan", "datetime", "disabled", "headers", "height", "high", "hspace", "label", "lang",
"list",
"low", "max", "maxlength", "min", "name", "nowrap", "placeholder", "required", "rev", "rows", "rowspan",
"rules", "selected", "size", "span", "spellcheck", "style", "summary", "tabindex", "title", "type",
"valign",
"value", "vspace", "width", "wrap"
]
// ReSharper restore StringLiteralTypo
};
/// <summary>
/// Параметры, оставляющие только текстовые теги, а также img и a
/// </summary>
/// <returns>Параметры очистки</returns>
private static SanitizerAllowedHtml GetImageAndLinks ()
{
// Получаю текстовые параметры
SanitizerAllowedHtml result = AllowedTextOnly;
// Добавляю теги
result.AllowedTags.AddRange(["a", "img"]);
// Добавляю параметры
// ReSharper disable StringLiteralTypo
result.AllowedAttributes.AddRange(["alt", "href", "hreflang", "nohref", "rel", "src", "target"]);
// ReSharper restore StringLiteralTypo
// Возвращаю результат
return result;
}
/// <summary>
/// Применяются все теги, кроме iframe
/// </summary>
/// <returns>Параметры очистки</returns>
private static SanitizerAllowedHtml GetAllExceptIFrame ()
{
// Получаю все параметры
SanitizerAllowedHtml result = AllowedAll;
// Удаляю iframe
result.AllowedTags.Remove("iframe");
// Возвращаю результат
return result;
}
#endregion
}

View File

@ -1,37 +0,0 @@
namespace anbs_cp.ForNet.Classes;
/// <summary>
/// Допустимые параметры для очистки HTML
/// </summary>
public sealed class SanitizerAllowedHtml
{
/// <summary>
/// Допустимые теги
/// </summary>
public List<string> AllowedTags { get; set; } = [];
/// <summary>
/// Допустимые аттрибуты
/// </summary>
public List<string> AllowedAttributes { get; set; } = [];
/// <summary>
/// Допустимые параметры css
/// </summary>
public List<string> AllowedCssProperties { get; set; } = [];
/// <summary>
/// Допустимые классы
/// </summary>
public List<string> AllowedClasses { get; set; } = [];
/// <summary>
/// Допустимые схемы
/// </summary>
public List<string> AllowedSchemes { get; set; } = [];
/// <summary>
/// Допустимы ли data-атрибуты
/// </summary>
public bool AllowDataAttributes { get; set; } = false;
}

View File

@ -1,41 +0,0 @@
using anbs_cp.Classes;
namespace anbs_cp.ForNet.Constants;
/// <summary>
/// Сообщения валидации
/// </summary>
public static class ValidationMessagesConstants
{
/// <summary>
/// Сообщения на русском языке
/// </summary>
public static readonly KeyValueOrderedList<string> 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}' не является номером кредитной карты.")
];
/// <summary>
/// Сообщения на английском языке
/// </summary>
public static readonly KeyValueOrderedList<string> 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.")
];
}

View File

@ -1,38 +0,0 @@
namespace anbs_cp.ForNet.Enums;
/// <summary>
/// Уровень очистки текста
/// атрибуты описаны на стр. https://github.com/mganss/HtmlSanitizer/wiki/Options
/// </summary>
public enum ESanitizerLevel
{
/// <summary>
/// Все html-теги под запретом
/// </summary>
NoTags = 0,
/// <summary>
/// Доступны только:
/// * теги формата шрифта (жирный, курсив, подчёркнутый, зачёркнутый)
/// * теги расположения текста (слева, по центру, справа)
/// </summary>
TextFormatOnly = 1,
/// <summary>
/// Доступны только:
/// * все теги уровня lvlTextFormatOnly
/// * теги ссылки
/// * теги изображения
/// </summary>
ImageAndLinks = 2,
/// <summary>
/// Доступны все теги, кроме вставки с другого сайта
/// </summary>
AllExceptIFrame = 3,
/// <summary>
/// Доступны все теги
/// </summary>
All = 4
}

View File

@ -1,108 +0,0 @@
using System.Text.RegularExpressions;
using ImageMagick;
using Microsoft.AspNetCore.Http;
using static System.Text.RegularExpressions.Regex;
namespace anbs_cp.ForNet.Extensions;
/// <summary>
/// Расширение интерфейса IFormFile
/// </summary>
public static class FormFileExtension
{
#region Константы
/// <summary>
/// Минимальный размер изображения (в байтах)
/// </summary>
private const int ImageMinimumBytes = 512;
/// <summary>
/// Список поддерживаемых Mime-типов
/// </summary>
private static readonly List<string> AllowedMimeTypes =
["image/jpg", "image/jpeg", "image/pjpeg", "image/gif", "image/x-png", "image/png"];
/// <summary>
/// Список поддерживаемых расширений файлов
/// </summary>
private static readonly List<string> AllowedExtensions = [".jpg", ".png", ".gif", ".jpeg"];
#endregion
/// <summary>
/// Получение содержимого файла
/// </summary>
/// <param name="file">Файл из формы</param>
/// <returns>Содержимое файла</returns>
public static byte[] GetFileContent (this IFormFile file)
{
// Читаем содержимое файла
using BinaryReader binaryReader = new(file.OpenReadStream());
// Создаю контент изображения
byte[] content = binaryReader.ReadBytes((int)file.Length);
// Вывожу результат
return content;
}
/// <summary>
/// Проверка, является ли файл изображением
/// </summary>
/// <param name="postedFile">Файл из формы</param>
/// <returns>Является ли файл изображением</returns>
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,
@"<script|<html|<head|<title|<body|<pre|<table|<a\s+href|<img|<plaintext|<cross\-domain\-policy",
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline))
return false;
}
catch (Exception)
{
// - если .NET выдаст исключение, то можно предположить, что это недопустимое изображение
return false;
}
// Попробую создать экземпляр MagickImageCollection,
try
{
using MagickImageCollection images = new(postedFile.OpenReadStream());
}
catch (Exception)
{
// - если .NET выдаст исключение, то можно предположить, что это недопустимое изображение
return false;
}
finally
{
postedFile.OpenReadStream().Position = 0;
}
// Возвращаю, что это изображение
return true;
}
}

View File

@ -1,110 +0,0 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Primitives;
namespace anbs_cp.ForNet.Extensions;
/// <summary>
/// Расширение URLHelper
/// </summary>
public static class UrlHelperExtension
{
/// <summary>
/// Очищает URL, удаляя ненужные QueryString
/// </summary>
/// <param name="helper">
/// <see cref="IUrlHelper" />
/// </param>
/// <param name="context">
/// <see cref="HttpContext" />
/// </param>
/// <param name="url">Ссылка, которую нужно почистить</param>
/// <param name="clearQueryString">Массив ключей, которые нужно удалить</param>
/// <param name="getLocalURL">Возвращать только локальную ссылку</param>
/// <returns></returns>
public static string ParseURLQuery(this IUrlHelper helper, HttpContext context, string? url,
string[] clearQueryString, bool getLocalURL = true)
{
//Получаю returnURL
url ??= "/";
//Если адрес локальный, то преобразую в полный
if (helper.IsLocalUrl(url))
url = LocalToFullURL(helper, context, url);
//Создаю uri по адресу
Uri uri = new(url ?? "");
//Формат
const UriFormat format = UriFormat.UriEscaped;
//Формирую Uri-адрес сайта
string baseUri =
uri.GetComponents(UriComponents.Scheme | UriComponents.Host | UriComponents.Port,
format);
//Формирую локальную ссылку
string localUri = uri.GetComponents(UriComponents.Path, format);
//Создаю словарь запроса
Dictionary<string, StringValues> query = QueryHelpers.ParseQuery(uri.Query);
//Если он содержит параметр для очистки, то удаляю его
foreach (KeyValuePair<string, StringValues> queryItem in query.Where(queryItem =>
clearQueryString.Contains(queryItem.Key)))
query.Remove(queryItem.Key);
//Создаю список запроса, пригодный для QueryBuilder
List<KeyValuePair<string, string>> queryList = query.Select(static queryItem =>
new KeyValuePair<string, string>(queryItem.Key, queryItem.Value.ToString())).ToList();
//Запускаю построение новых параметров
QueryBuilder qBuilder = new(queryList);
//Создаю переменную-результат
string result = "";
//Если нужно получить полную ссылку
if (!getLocalURL)
result = baseUri;
//формирую переменную-результат
result = $"{result}/{localUri}{qBuilder.ToQueryString()}";
//Вывожу результат
return result;
}
/// <summary>
/// Получает локальный url-адрес
/// </summary>
/// <param name="helper"><see cref="IUrlHelper" /></param>
/// <param name="url">url-адрес</param>
/// <returns>Локальный url-адрес</returns>
public static string ToLocalURL (this IUrlHelper helper, string url)
{
//Создаю uri из url
Uri uri = new(url);
//Вывожу результат
return helper.IsLocalUrl(url) ? url : uri.PathAndQuery;
}
/// <summary>
/// Преобразует локальную ссылку в полную
/// </summary>
/// <param name="helper">
/// <see cref="IUrlHelper" />
/// </param>
/// <param name="context">
/// <see cref="HttpContext" />
/// </param>
/// <param name="url">Ссылка</param>
/// <returns>
/// <see cref="string" />
/// </returns>
public static string? LocalToFullURL (this IUrlHelper helper, HttpContext context, string? url) =>
helper.IsLocalUrl(url) ? $"{context.Request.Scheme}://{context.Request.Host}{url}" : url;
}

View File

@ -1,37 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageId>ANBSoftware.ComponentsPackForNet</PackageId>
<Version>2024.9.1</Version>
<Authors>Александр Бабаев</Authors>
<Product>Набор компонентов ANB Software для ASP.NET Core</Product>
<Description>Библиотека полезных методов языка C# для ASP.NET Core</Description>
<Copyright>Александр Бабаев</Copyright>
<PackageProjectUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</PackageProjectUrl>
<RepositoryUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RootNamespace>anbs_cp.ForNet</RootNamespace>
<AssemblyName>anbs_cp_fn</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HtmlSanitizer" Version="8.1.870" />
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="13.10.0" />
<PackageReference Include="Magick.NET.Core" Version="13.10.0" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Html.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.TagHelpers" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.8" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\anbs_cp\anbs_cp.csproj" />
</ItemGroup>
</Project>

View File

@ -1,59 +0,0 @@
using anbs_cp.OsInfo.Enums;
using anbs_cp.OsInfo.Interfaces;
namespace anbs_cp.OsInfo.Classes;
/// <summary>
/// Информация о дисках
/// </summary>
public sealed class OsDriveInfo: IOsDriveInfo
{
/// <summary>
/// Конструктор
/// </summary>
public OsDriveInfo ()
{
Type = EDriveType.DtHardDisc;
Caption = null;
Description = null;
DeviceId = null;
Name = null;
Model = null;
TotalSize = 0;
}
/// <summary>
/// Тип диска
/// </summary>
public EDriveType Type { get; set; }
/// <summary>
/// Заголовок
/// </summary>
public string? Caption { get; set; }
/// <summary>
/// Описание
/// </summary>
public string? Description { get; set; }
/// <summary>
/// Идентификатор устройства
/// </summary>
public string? DeviceId { get; set; }
/// <summary>
/// Имя устройства
/// </summary>
public string? Name { get; set; }
/// <summary>
/// Модель
/// </summary>
public string? Model { get; set; }
/// <summary>
/// Общий размер
/// </summary>
public ulong TotalSize { get; set; }
}

View File

@ -1,402 +0,0 @@
using System.Management;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using anbs_cp.Classes;
using anbs_cp.OsInfo.Enums;
using anbs_cp.OsInfo.Interfaces;
namespace anbs_cp.OsInfo.Classes;
/// <summary>
/// Информация о системе
/// </summary>
public static class OsInfo
{
/// <summary>
/// Конструктор
/// </summary>
static OsInfo ()
{
Windows = GetWindowsInfo();
Processors = GetProcessors();
RAM = GetRAMs();
Videos = GetVideoAdapterInfos();
Drives = GetDriveInfos();
Net = GetNet();
}
/// <summary>
/// Информация о Windows
/// </summary>
public static IOsWindowsInfo Windows { get; }
/// <summary>
/// Список с информацией о процессоре(-ах)
/// </summary>
public static List<IOsProcessorInfo> Processors { get; }
/// <summary>
/// Количество оперативной памяти в байтах
/// </summary>
public static ulong RAM { get; }
/// <summary>
/// Видеоадаптеры
/// </summary>
public static List<IOsVideoAdapterInfo> Videos { get; }
/// <summary>
/// Диски
/// </summary>
public static List<IOsDriveInfo> Drives { get; set; }
/// <summary>
/// Сеть
/// </summary>
public static List<IOsNetInfo> Net { get; set; }
#region Служебные методы
/// <summary>
/// Получает информацию о Windows
/// </summary>
/// <returns></returns>
private static IOsWindowsInfo GetWindowsInfo () =>
new OsWindowsInfo
{
Version = Environment.OSVersion.ToString(),
Is64 = Environment.Is64BitOperatingSystem,
PcName = Environment.MachineName,
WindowsFolder = Environment.SystemDirectory
};
/// <summary>
/// Получение процессоров
/// </summary>
/// <returns>Список информации о процессорах</returns>
private static List<IOsProcessorInfo> GetProcessors ()
{
try
{
//Создаю результирующий список
List<IOsProcessorInfo> processorsList = new();
//Создаю классы менеджмента
ManagementClass management = new("Win32_Processor");
ManagementObjectCollection collection = management.GetInstances();
//Получаю число процессоров
int processorsCount = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["ProcessorId"].Value.ToString()).Count();
//Перебираю массив данных
for (int ind = 0; ind < processorsCount; ind++)
{
//Создаю элемент информации о процессоре
OsProcessorInfo processor = new()
{
Caption = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Caption"].Value.ToString()).ElementAtOrDefault(ind),
Description = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Description"].Value.ToString()).ElementAtOrDefault(ind),
DeviceId = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["DeviceID"].Value.ToString()).ElementAtOrDefault(ind),
Manufacturer = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Manufacturer"].Value.ToString()).ElementAtOrDefault(ind),
MaxClockSpeed = TypeConverter.StrToInt(collection.Cast<ManagementObject>()
.Select(static a =>
a.Properties["MaxClockSpeed"].Value.ToString())
.ElementAtOrDefault(ind) ??
"0"),
Name = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Name"].Value.ToString()).ElementAtOrDefault(ind),
NumberOfCores = TypeConverter.StrToInt(collection.Cast<ManagementObject>()
.Select(static a =>
a.Properties["NumberOfCores"].Value.ToString())
.ElementAtOrDefault(ind) ??
"0"),
NumberOfLogicalProcessors = TypeConverter.StrToInt(collection.Cast<ManagementObject>()
.Select(static a => a.Properties["NumberOfLogicalProcessors"].Value.ToString())
.ElementAtOrDefault(ind) ?? "0")
};
//Добавляю в список
processorsList.Add(processor);
}
//Возвращаю список
return processorsList;
}
catch (NullReferenceException)
{
return new();
}
}
/// <summary>
/// Получение общее количество оперативной памяти
/// </summary>
/// <returns>Список информации о количестве оперативной памяти</returns>
private static ulong GetRAMs ()
{
try
{
//Создаю классы менеджмента
ManagementClass management = new("Win32_ComputerSystem");
ManagementObjectCollection collection = management.GetInstances();
//Получаю результат
return TypeConverter.StrToUInt64(collection.Cast<ManagementObject>()
.Select(static a => a.Properties["TotalPhysicalMemory"].Value.ToString()).FirstOrDefault() ?? "0");
}
catch (NullReferenceException)
{
return 0;
}
}
/// <summary>
/// Получает список видеоадаптеров
/// </summary>
/// <returns>Список информации о видеоадаптерах</returns>
private static List<IOsVideoAdapterInfo> GetVideoAdapterInfos ()
{
try
{
//Создаю результирующий список
List<IOsVideoAdapterInfo> videosList = new();
//Создаю классы менеджмента
ManagementClass management = new("Win32_VideoController");
ManagementObjectCollection collection = management.GetInstances();
//Получаю число адаптеров
int count = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["DeviceID"].Value.ToString()).Count();
//Перебираю массив данных
for (int ind = 0; ind < count; ind++)
{
//Создаю элемент информации об адаптере
OsVideoAdapterInfo adapter = new()
{
Caption = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Caption"].Value.ToString()).ElementAtOrDefault(ind),
Description = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Description"].Value.ToString()).ElementAtOrDefault(ind),
DeviceId = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["DeviceID"].Value.ToString()).ElementAtOrDefault(ind),
AdapterRAM = TypeConverter.StrToInt(collection.Cast<ManagementObject>()
.Select(static a => a.Properties["AdapterRAM"].Value.ToString()).ElementAtOrDefault(ind) ?? "0"),
DriverDate = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["DriverDate"].Value.ToString()).ElementAtOrDefault(ind),
Name = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Name"].Value.ToString()).ElementAtOrDefault(ind),
CurrentResolution = (TypeConverter.StrToInt(collection.Cast<ManagementObject>()
.Select(static a => a.Properties["CurrentHorizontalResolution"].Value.ToString()).ElementAtOrDefault(ind) ?? "0"),
TypeConverter.StrToInt(collection.Cast<ManagementObject>()
.Select(static a => a.Properties["CurrentVerticalResolution"].Value.ToString())
.ElementAtOrDefault(ind) ?? "0")),
SystemName = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["SystemName"].Value.ToString()).ElementAtOrDefault(ind),
DriverVersion = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["DriverVersion"].Value.ToString()).ElementAtOrDefault(ind),
InstalledDisplayDrivers = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["InstalledDisplayDrivers"].Value.ToString()).ElementAtOrDefault(ind),
VideoProcessor = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["VideoProcessor"].Value.ToString()).ElementAtOrDefault(ind)
};
//Добавляю в список
videosList.Add(adapter);
}
//Возвращаю список
return videosList;
}
catch (NullReferenceException)
{
return new();
}
}
/// <summary>
/// Получает список дисков
/// </summary>
/// <returns>Список информации о дисках</returns>
private static List<IOsDriveInfo> GetDriveInfos ()
{
try
{
//Создаю результат
List<IOsDriveInfo> result = new();
//Добавление всех HDD/SSD дисков
result.AddRange(GetHDDs());
//Добавление всех CD/DVD/BD дисков
result.AddRange(GetCDRom());
//Вывожу список
return result;
}
catch (NullReferenceException)
{
return new();
}
}
/// <summary>
/// Получаю список HDD/SSD дисков
/// </summary>
/// <returns>Информация обо всех HDD/SSD дисках</returns>
private static List<IOsDriveInfo> GetHDDs ()
{
try
{
//Создаю результирующий список
List<IOsDriveInfo> driveList = new();
//Создаю классы менеджмента
ManagementClass management = new("Win32_DiskDrive");
ManagementObjectCollection collection = management.GetInstances();
//Получаю число адаптеров
int count = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["DeviceID"].Value.ToString()).Count();
//Перебираю массив данных
for (int ind = 0; ind < count; ind++)
{
//Создаю элемент информации об адаптере
OsDriveInfo drive = new()
{
Type = EDriveType.DtHardDisc,
Caption = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Caption"].Value.ToString()).ElementAtOrDefault(ind),
Description = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Description"].Value.ToString()).ElementAtOrDefault(ind),
DeviceId = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["DeviceID"].Value.ToString()).ElementAtOrDefault(ind),
Name = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Name"].Value.ToString()).ElementAtOrDefault(ind),
TotalSize = TypeConverter.StrToUInt64(collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Size"].Value.ToString()).ElementAtOrDefault(ind) ?? "0"),
Model = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Model"].Value.ToString()).ElementAtOrDefault(ind)
};
//Добавляю в список
driveList.Add(drive);
}
//Возвращаю список
return driveList;
}
catch (NullReferenceException)
{
return new();
}
}
/// <summary>
/// Получаю список CD/DVD/BD дисков
/// </summary>
/// <returns>Информация обо всех CD/DVD/BD дисках</returns>
private static List<IOsDriveInfo> GetCDRom ()
{
try
{
//Создаю результирующий список
List<IOsDriveInfo> driveList = new();
//Создаю классы менеджмента
ManagementClass management = new("Win32_CDROMDrive");
ManagementObjectCollection collection = management.GetInstances();
//Получаю число адаптеров
int count = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["DeviceID"].Value.ToString()).Count();
//Перебираю массив данных
for (int ind = 0; ind < count; ind++)
{
//Создаю элемент информации об адаптере
OsDriveInfo drive = new()
{
Type = EDriveType.DtCDRom,
Caption = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Caption"].Value.ToString()).ElementAtOrDefault(ind),
Description = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Description"].Value.ToString()).ElementAtOrDefault(ind),
DeviceId = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["DeviceID"].Value.ToString()).ElementAtOrDefault(ind),
Name = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Name"].Value.ToString()).ElementAtOrDefault(ind),
//Ставится 0, чтобы не проверять корректность загрузки и читаемость диска, а также избежать удлинения получения информации
TotalSize = 0,
Model = collection.Cast<ManagementObject>()
.Select(static a => a.Properties["Manufacturer"].Value.ToString()).ElementAtOrDefault(ind)
};
//Добавляю в список
driveList.Add(drive);
}
//Возвращаю список
return driveList;
}
catch (NullReferenceException)
{
return new();
}
}
/// <summary>
/// Получаю информацию о сети интернет
/// </summary>
/// <returns>Информация о сети интернет</returns>
private static List<IOsNetInfo> GetNet ()
{
try
{
//Создаю результирующий список
List<IOsNetInfo> netList = new();
//Получаю информацию о всех сетевых интерфейсах
foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces())
{
//Создаю элемент
OsNetInfo netInfo = new()
{
Name = adapter.Name,
Description = adapter.Description,
MacAddress = adapter.OperationalStatus == OperationalStatus.Up
? adapter.GetPhysicalAddress().ToString()
: null
};
//Получаю IP-адрес
foreach (UnicastIPAddressInformation info in adapter.GetIPProperties().UnicastAddresses.Where(
static info =>
info.Address.AddressFamily == AddressFamily.InterNetwork && info.IsDnsEligible))
{
if (!string.IsNullOrWhiteSpace(netInfo.IPAddress))
netInfo.IPAddress += ";";
netInfo.IPAddress += info.Address.ToString();
}
//Добавляю адаптер
netList.Add(netInfo);
}
//Возвращаю список
return netList;
}
catch (NullReferenceException)
{
return new();
}
}
#endregion
}

View File

@ -1,39 +0,0 @@
using anbs_cp.OsInfo.Interfaces;
namespace anbs_cp.OsInfo.Classes;
/// <summary>
/// Информация об интернет-соединении
/// </summary>
public sealed class OsNetInfo: IOsNetInfo
{
/// <summary>
/// Заголовок
/// </summary>
public string? Caption { get => Name; set => _ = value; }
/// <summary>
/// Описание
/// </summary>
public string? Description { get; set; }
/// <summary>
/// Идентификатор устройства
/// </summary>
public string? DeviceId { get => Name; set => _ = value; }
/// <summary>
/// Имя устройства
/// </summary>
public string? Name { get; set; }
/// <summary>
/// IP-адрес
/// </summary>
public string? IPAddress { get; set; }
/// <summary>
/// MAC-адрес
/// </summary>
public string? MacAddress { get; set; }
}

View File

@ -1,64 +0,0 @@
using anbs_cp.OsInfo.Interfaces;
namespace anbs_cp.OsInfo.Classes;
/// <summary>
/// Класс информации о процессоре
/// </summary>
public sealed class OsProcessorInfo: IOsProcessorInfo
{
/// <summary>
/// Конструктор
/// </summary>
public OsProcessorInfo ()
{
Caption = null;
Description = null;
DeviceId = null;
Manufacturer = null;
MaxClockSpeed = 0;
Name = null;
NumberOfCores = 0;
NumberOfLogicalProcessors = 0;
}
/// <summary>
/// Заголовок
/// </summary>
public string? Caption { get; set; }
/// <summary>
/// Описание
/// </summary>
public string? Description { get; set; }
/// <summary>
/// Идентификатор процессора в системе
/// </summary>
public string? DeviceId { get; set; }
/// <summary>
/// Производитель
/// </summary>
public string? Manufacturer { get; set; }
/// <summary>
/// Максимальная тактовая частота
/// </summary>
public int MaxClockSpeed { get; set; }
/// <summary>
/// Имя процессора
/// </summary>
public string? Name { get; set; }
/// <summary>
/// Число ядер
/// </summary>
public int NumberOfCores { get; set; }
/// <summary>
/// Число потоков
/// </summary>
public int NumberOfLogicalProcessors { get; set; }
}

View File

@ -1,82 +0,0 @@
using anbs_cp.OsInfo.Interfaces;
namespace anbs_cp.OsInfo.Classes;
/// <summary>
/// Информация о видеокарте
/// </summary>
internal sealed class OsVideoAdapterInfo: IOsVideoAdapterInfo
{
/// <summary>
/// Конструктор
/// </summary>
public OsVideoAdapterInfo ()
{
AdapterRAM = 0;
Caption = null;
CurrentResolution = (0, 0);
Description = null;
DeviceId = null;
DriverDate = null;
DriverVersion = null;
InstalledDisplayDrivers = null;
Name = null;
SystemName = null;
VideoProcessor = null;
}
/// <summary>
/// Память
/// </summary>
public int AdapterRAM { get; set; }
/// <summary>
/// Заголовок
/// </summary>
public string? Caption { get; set; }
/// <summary>
/// Текущее разрешение
/// </summary>
public (int, int) CurrentResolution { get; set; }
/// <summary>
/// Описание
/// </summary>
public string? Description { get; set; }
/// <summary>
/// Идентификатор устройства
/// </summary>
public string? DeviceId { get; set; }
/// <summary>
/// Дата установки драйвера
/// </summary>
public string? DriverDate { get; set; }
/// <summary>
/// Версия драйвера
/// </summary>
public string? DriverVersion { get; set; }
/// <summary>
/// Название драйверов
/// </summary>
public string? InstalledDisplayDrivers { get; set; }
/// <summary>
/// Имя
/// </summary>
public string? Name { get; set; }
/// <summary>
/// Имя в системе
/// </summary>
public string? SystemName { get; set; }
/// <summary>
/// Видео процессор
/// </summary>
public string? VideoProcessor { get; set; }
}

View File

@ -1,62 +0,0 @@
using anbs_cp.OsInfo.Interfaces;
namespace anbs_cp.OsInfo.Classes;
/// <summary>
/// Информация о Windows
/// </summary>
public sealed class OsWindowsInfo: IOsWindowsInfo
{
/// <summary>
/// Конструктор
///</summary>
public OsWindowsInfo ()
{
Version = null;
Is64 = true;
PcName = null;
WindowsFolder = null;
}
/// <summary>
/// Версия
/// </summary>
public string? Version { get; set; }
/// <summary>
/// 64-разрядная ОС
/// </summary>
public bool Is64 { get; set; }
/// <summary>
/// Имя компьютера
/// </summary>
public string? PcName { get; set; }
/// <summary>
/// Путь к папке Windows
/// </summary>
public string? WindowsFolder { get; set; }
#region Реализация интерфейса IBasicInfo
/// <summary>
/// Заголовок
/// </summary>
public string? Caption { get => Version; set => _ = value; }
/// <summary>
/// Описание
/// </summary>
public string? Description { get => Version; set => _ = value; }
/// <summary>
/// Идентификатор
/// </summary>
public string? DeviceId { get => Version; set => _ = value; }
/// <summary>
/// Имя
/// </summary>
public string? Name { get => Version; set => _ = value; }
#endregion
}

View File

@ -1,17 +0,0 @@
namespace anbs_cp.OsInfo.Enums;
/// <summary>
/// Тип носителя
/// </summary>
public enum EDriveType
{
/// <summary>
/// HDD/SSD/M2
/// </summary>
DtHardDisc = 0,
/// <summary>
/// Диск CD/DVD/BD
/// </summary>
DtCDRom = 1
}

View File

@ -1,27 +0,0 @@
namespace anbs_cp.OsInfo.Interfaces;
/// <summary>
/// Базовые параметры устройства
/// </summary>
public interface IOsBasicInfo
{
/// <summary>
/// Заголовок
/// </summary>
public string? Caption { get; set; }
/// <summary>
/// Описание
/// </summary>
public string? Description { get; set; }
/// <summary>
/// Идентификатор устройства
/// </summary>
public string? DeviceId { get; set; }
/// <summary>
/// Имя устройства
/// </summary>
public string? Name { get; set; }
}

View File

@ -1,24 +0,0 @@
using anbs_cp.OsInfo.Enums;
namespace anbs_cp.OsInfo.Interfaces;
/// <summary>
/// Информация о дисках
/// </summary>
public interface IOsDriveInfo: IOsBasicInfo
{
/// <summary>
/// Тип диска
/// </summary>
public EDriveType Type { get; set; }
/// <summary>
/// Модель
/// </summary>
public string? Model { get; set; }
/// <summary>
/// Общий размер
/// </summary>
public ulong TotalSize { get; set; }
}

View File

@ -1,17 +0,0 @@
namespace anbs_cp.OsInfo.Interfaces;
/// <summary>
/// Информация об интернет-соединении
/// </summary>
public interface IOsNetInfo: IOsBasicInfo
{
/// <summary>
/// IP-адрес
/// </summary>
public string? IPAddress { get; set; }
/// <summary>
/// MAC-адрес
/// </summary>
public string? MacAddress { get; set; }
}

View File

@ -1,31 +0,0 @@
namespace anbs_cp.OsInfo.Interfaces;
/// <summary>
/// Информация о процессоре
/// </summary>
public interface IOsProcessorInfo: IOsBasicInfo
{
/// <summary>
/// Заголовок
/// </summary>
/// <summary>
/// Производитель
/// </summary>
public string? Manufacturer { get; set; }
/// <summary>
/// Максимальная тактовая частота
/// </summary>
public int MaxClockSpeed { get; set; }
/// <summary>
/// Число ядер
/// </summary>
public int NumberOfCores { get; set; }
/// <summary>
/// Число потоков
/// </summary>
public int NumberOfLogicalProcessors { get; set; }
}

View File

@ -1,42 +0,0 @@
namespace anbs_cp.OsInfo.Interfaces;
/// <summary>
/// Информация о видеокарте
/// </summary>
public interface IOsVideoAdapterInfo: IOsBasicInfo
{
/// <summary>
/// Память
/// </summary>
public int AdapterRAM { get; set; }
/// <summary>
/// Текущее разрешение
/// </summary>
public (int, int) CurrentResolution { get; set; }
/// <summary>
/// Дата установки драйвера
/// </summary>
public string? DriverDate { get; set; }
/// <summary>
/// Версия драйвера
/// </summary>
public string? DriverVersion { get; set; }
/// <summary>
/// Название драйверов
/// </summary>
public string? InstalledDisplayDrivers { get; set; }
/// <summary>
/// Имя в системе
/// </summary>
public string? SystemName { get; set; }
/// <summary>
/// Видео процессор
/// </summary>
public string? VideoProcessor { get; set; }
}

View File

@ -1,27 +0,0 @@
namespace anbs_cp.OsInfo.Interfaces;
/// <summary>
/// Информация о Windows
/// </summary>
public interface IOsWindowsInfo: IOsBasicInfo
{
/// <summary>
/// Версия
/// </summary>
public string? Version { get; set; }
/// <summary>
/// 64-разрядная ОС
/// </summary>
public bool Is64 { get; set; }
/// <summary>
/// Имя компьютера
/// </summary>
public string? PcName { get; set; }
/// <summary>
/// Путь к папке Windows
/// </summary>
public string? WindowsFolder { get; set; }
}

View File

@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>anbs_cp.OsInfo</RootNamespace>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageId>ANBSoftware.ComponentsPackOsInfo</PackageId>
<Version>2023.11.14</Version>
<Authors>Александр Бабаев</Authors>
<Product>Набор компонентов ANB Software для получения информации о Windows</Product>
<Description>Библиотека полезных методов языка C# для получения информации об Windows</Description>
<Copyright>Александр Бабаев</Copyright>
<PackageProjectUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</PackageProjectUrl>
<RepositoryUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Management" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\anbs_cp\anbs_cp.csproj" />
</ItemGroup>
</Project>

View File

@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp120</s:String></wpf:ResourceDictionary>

View File

@ -5,24 +5,11 @@ VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "anbs_cp", "anbs_cp\anbs_cp.csproj", "{442A56CC-1061-4EB5-8B67-3E3D997976D7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "demo", "demo\demo.csproj", "{3BB0778D-3C34-4DD8-A54E-CB476BEF2F7B}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo", "demo\demo.csproj", "{3BB0778D-3C34-4DD8-A54E-CB476BEF2F7B}"
ProjectSection(ProjectDependencies) = postProject
{442A56CC-1061-4EB5-8B67-3E3D997976D7} = {442A56CC-1061-4EB5-8B67-3E3D997976D7}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "anbs_cpfn", "anbs_cpfn\anbs_cpfn.csproj", "{EDED871B-8A96-4A2F-83CF-AD40FF66F6E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "anbs_cposinfo", "anbs_cposinfo\anbs_cposinfo.csproj", "{80E1FEA9-EEDA-4411-8EBA-11991432E98E}"
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
@ -36,22 +23,6 @@ Global
{3BB0778D-3C34-4DD8-A54E-CB476BEF2F7B}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{3BB0778D-3C34-4DD8-A54E-CB476BEF2F7B}.Debug|Any CPU.Build.0 = Release|Any CPU
{3BB0778D-3C34-4DD8-A54E-CB476BEF2F7B}.Release|Any CPU.ActiveCfg = Debug.CNF|Any CPU
{EDED871B-8A96-4A2F-83CF-AD40FF66F6E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EDED871B-8A96-4A2F-83CF-AD40FF66F6E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EDED871B-8A96-4A2F-83CF-AD40FF66F6E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EDED871B-8A96-4A2F-83CF-AD40FF66F6E2}.Release|Any CPU.Build.0 = Release|Any CPU
{80E1FEA9-EEDA-4411-8EBA-11991432E98E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{80E1FEA9-EEDA-4411-8EBA-11991432E98E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{80E1FEA9-EEDA-4411-8EBA-11991432E98E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80E1FEA9-EEDA-4411-8EBA-11991432E98E}.Release|Any CPU.Build.0 = Release|Any CPU
{3796862F-F181-4A27-92D8-8BF13C4FD711}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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

View File

@ -1,57 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CD/@EntryIndexedValue">CD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HD/@EntryIndexedValue">HD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HDD/@EntryIndexedValue">HDD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RA/@EntryIndexedValue">RA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RAM/@EntryIndexedValue">RAM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=URL/@EntryIndexedValue">URL</s:String>
<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=_0412_044B_0447_0438_0441_043B_044F_0435_0442_002C_0020_0435_0441_0442_044C_0020_043B_0438_0020_0445_043E_0442_044F_0020_0431_044B_0020_043E_0434_043D_043E_0020_0438_0437_0020_0431_0443_043B_0435_0432_044B_0445_0020_043F_0435_0440_0435_043C_0435_043D_043D_044B_0445_0020reference_0432_0020_0437_043D_0430_0447_0435_043D_0438_0438/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=abcdefghijkmnopqrstuvwxyz/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ABCDEFGHJKLMNOPQRSTUVWXYZ/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=anbs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=appsettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=C_0435_0440_0438_0430_043B_0438_0437_0430_0446_0438_044F/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Darkseal/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=delim/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Encryptor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Glendower/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pjpeg/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=splited/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0412_0435_0440_043D_0451_043C/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0412_0438_0434_0435_043E_043A_0430_0440_0442_0430/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0414_0435_0441_0435_0440_0438_0430_043B_0438_0437_043E_0432_0430_043D_043D_044B_0439/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0414_0435_0441_0435_0440_0438_0430_043B_0438_0437_0443_0435_043C/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0414_0435_0441_0435_0440_0438_0430_043B_0438_0437_0443_044E/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_041F_0430_0440_0441_0435_0440/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0421_0435_0440_0438_0430_043B_0438_0437_043E_0432_0430_043D_043D_0430_044F/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0421_0435_0440_0438_0430_043B_0438_0437_043E_0432_0430_043D_043D_044B_0435/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0421_0435_0440_0438_0430_043B_0438_0437_043E_0432_0430_0442_044C/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0421_0435_0440_0438_0430_043B_0438_0437_0443_0435_043C_043E_0435/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0421_043E_0437_0434_0430_0451_043C/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0432_0432_0435_0434_0451_043D/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0432_0438_0434_0435_043E_043A_0430_0440_0442_0435/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0434_0435_0441_0435_0440_0438_0430_043B_0438_0437_0430_0446_0438_0435_0439/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0434_0435_0441_0435_0440_0438_0430_043B_0438_0437_0430_0446_0438_0438/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0434_0435_0441_0435_0440_0438_0430_043B_0438_0437_0430_0446_0438_044F/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0434_0435_0448_0438_0444_0440_043E_0432_0430_043D_0438_044F/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0434_0435_0448_0438_0444_0440_043E_0432_0447_0438_043A/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0437_0430_0447_0451_0440_043A_043D_0443_0442_044B_0439/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0438_043C_0451_043D/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_043A_0440_0438_043F_0442_043E_0433_0440_0430_0444/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_043F_043E_0434_0447_0451_0440_043A_043D_0443_0442_044B_0439/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_043F_0443_0442_0451_043C/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0440_0435_0433_0438_0441_0442_0440_043E_0437_0430_0432_0438_0441_0438_043C_043E_0441_0442_044C/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0435_0440_0438_0430_043B_0438_0437_0430_0442_043E_0440_0430/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0435_0440_0438_0430_043B_0438_0437_0430_0446_0438_0438/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0435_0440_0438_0430_043B_0438_0437_0430_0446_0438_044F/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0435_0440_0438_0430_043B_0438_0437_043E_0432_0430_043D_043D_043E_0433_043E/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0435_0440_0438_0430_043B_0438_0437_043E_0432_0430_043D_043D_043E_0435/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0435_0440_0438_0430_043B_0438_0437_043E_0432_0430_043D_043D_0443_044E/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0435_0440_0438_0430_043B_0438_0437_0443_0435_043C/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0435_0440_0438_0430_043B_0438_0437_0443_044E/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0447_0451_0442/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_0447_0451_0442_0447_0438_043A/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0445_044D_0448_0430/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0445_044D_0448_0435_043C/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0445_044D_0448_0435_0440/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -1,92 +0,0 @@
namespace demo;
sealed partial class ActionStateSerialize
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose (bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}

View File

@ -1,34 +0,0 @@
using anbs_cp.Classes;
namespace demo;
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<DemoClass> state = new()
{
Value = demoClass
};
state.AddError("ОШИБКА, ШЕФ!");
textBox2.Text = state.Serialize();
ActionState<DemoClass> state2 = new();
state2.Deserialize(textBox2.Text);
label1.Text = state2.Value?.Name ?? "НЕТ ЗНАЧЕНИЯ";
}
}

View File

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -1,6 +1,6 @@
namespace demo;
sealed partial class CountValueTest
namespace demo
{
partial class CountValueTest
{
/// <summary>
/// Required designer variable.
@ -34,7 +34,6 @@ sealed partial class CountValueTest
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
@ -42,17 +41,16 @@ sealed partial class CountValueTest
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.Size = new System.Drawing.Size(197, 17);
this.InsertDataLabel.TabIndex = 0;
this.InsertDataLabel.Text = "&Введите любое целочисленное значение:";
this.InsertDataLabel.Text = "&Insert any int value:";
//
// 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.Size = new System.Drawing.Size(246, 24);
this.InsertDataBox.TabIndex = 1;
this.InsertDataBox.TextChanged += new System.EventHandler(this.InsertDataBox_TextChanged);
//
// ResultLabel
//
@ -61,19 +59,19 @@ sealed partial class CountValueTest
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.Size = new System.Drawing.Size(270, 79);
this.ResultLabel.TabIndex = 2;
this.ResultLabel.Text = "&Вставьте любое целочисленное значение в поле выше и нажмите кнопку \"Вычислить\", " +
"чтобы увидеть результат...";
this.ResultLabel.Text = "&Insert any int value to insert box above and press \"Calculate\" button to see res" +
"ult...";
this.ResultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// CalculateButton
//
this.CalculateButton.Location = new System.Drawing.Point(12, 116);
this.CalculateButton.Location = new System.Drawing.Point(81, 116);
this.CalculateButton.Name = "CalculateButton";
this.CalculateButton.Size = new System.Drawing.Size(234, 23);
this.CalculateButton.Size = new System.Drawing.Size(103, 23);
this.CalculateButton.TabIndex = 3;
this.CalculateButton.Text = "В&ычислить обработчиком";
this.CalculateButton.Text = "Calc&ulate";
this.CalculateButton.UseVisualStyleBackColor = true;
this.CalculateButton.Click += new System.EventHandler(this.CalculateButton_Click);
//
@ -82,9 +80,9 @@ sealed partial class CountValueTest
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.Size = new System.Drawing.Size(161, 17);
this.SelectFormatterLabel.TabIndex = 4;
this.SelectFormatterLabel.Text = "В&ыберете обработчик:";
this.SelectFormatterLabel.Text = "&Select formatter:";
//
// SelectFormatterBox
//
@ -92,29 +90,18 @@ sealed partial class CountValueTest
this.SelectFormatterBox.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.SelectFormatterBox.FormattingEnabled = true;
this.SelectFormatterBox.Items.AddRange(new object[] {
"Обработчик счёта",
"Обработчик размера файла"});
"CountFormatter",
"FileSizeFormatter"});
this.SelectFormatterBox.Location = new System.Drawing.Point(12, 29);
this.SelectFormatterBox.Name = "SelectFormatterBox";
this.SelectFormatterBox.Size = new System.Drawing.Size(457, 25);
this.SelectFormatterBox.Size = new System.Drawing.Size(246, 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.ClientSize = new System.Drawing.Size(270, 222);
this.Controls.Add(this.SelectFormatterBox);
this.Controls.Add(this.SelectFormatterLabel);
this.Controls.Add(this.CalculateButton);
@ -128,7 +115,7 @@ sealed partial class CountValueTest
this.Name = "CountValueTest";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Тест модуля форматирования строки";
this.Text = "Formatter Test Unit";
this.Load += new System.EventHandler(this.CountValueTest_Load);
this.ResumeLayout(false);
this.PerformLayout();
@ -143,5 +130,5 @@ sealed partial class CountValueTest
private Button CalculateButton;
private Label SelectFormatterLabel;
private ComboBox SelectFormatterBox;
private Button calculateConvButton;
}
}

View File

@ -1,9 +1,7 @@
using anbs_cp.Classes;
using anbs_cp.Interfaces;
namespace demo;
public sealed partial class CountValueTest: Form
using anbs_cp;
namespace demo
{
public partial class CountValueTest : Form
{
public CountValueTest()
{
@ -16,13 +14,23 @@ public sealed partial class CountValueTest: Form
if (string.IsNullOrEmpty(InsertDataBox.Text))
return;
IValueFormatter formatter;
long value = TypeConverter.StrToInt64(InsertDataBox.Text);
IValueFormatter formatter = SelectFormatterBox.SelectedIndex switch
switch (SelectFormatterBox.SelectedIndex)
{
0 => new CountFormatter(),
1 => new FileSizeFormatter(),
_ => new CountFormatter(),
};
case 0:
formatter = new CountFormatter();
break;
case 1:
formatter = new FileSizeFormatter();
break;
default:
formatter = new CountFormatter();
break;
}
ResultLabel.Text = formatter.Format(value);
}
@ -30,27 +38,5 @@ public sealed partial class CountValueTest: Form
{
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)
};
}
}

View File

@ -1,8 +0,0 @@
namespace demo;
public class DemoClass
{
public int Num { get; set; } = 5;
public string Name { get; set; } = "";
public bool NotB { get; set; } = true;
}

View File

@ -1,125 +0,0 @@
namespace demo;
sealed partial class FileHashAndMimeType
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose (bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}

View File

@ -1,44 +0,0 @@
using anbs_cp.Classes;
using anbs_cp.Extensions;
// ReSharper disable LocalizableElement
namespace demo;
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();
}
}

View File

@ -1,63 +0,0 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="openFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

Some files were not shown because too many files have changed in this diff Show More