san40_u5an40.ExtraLib 5.4.0

dotnet add package san40_u5an40.ExtraLib --version 5.4.0
                    
NuGet\Install-Package san40_u5an40.ExtraLib -Version 5.4.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="san40_u5an40.ExtraLib" Version="5.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="san40_u5an40.ExtraLib" Version="5.4.0" />
                    
Directory.Packages.props
<PackageReference Include="san40_u5an40.ExtraLib" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add san40_u5an40.ExtraLib --version 5.4.0
                    
#r "nuget: san40_u5an40.ExtraLib, 5.4.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package san40_u5an40.ExtraLib@5.4.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=san40_u5an40.ExtraLib&version=5.4.0
                    
Install as a Cake Addin
#tool nuget:?package=san40_u5an40.ExtraLib&version=5.4.0
                    
Install as a Cake Tool

san40_u5an40.ExtraLib

В данном NuGet-пакете представлена библиотека классов, расширяющая стандартные возможности программирования. В ней представлены паттерны, полезные как при процедурном стиле программирования, так и при объектно-ориентированном.

Оглавление:

Ядро (san40_u5an40.ExtraLib.Core):

Паттерны (san40_u5an40.ExtraLib.Patterns):

Валидация (san40_u5an40.ExtraLib.Validation):

Обработка данных (san40_u5an40.ExtraLib.Data):

Ввод-вывод (san40_u5an40.ExtraLib.IO):

Рефлексия (san40_u5an40.ExtraLib.Reflection):

Bytes

Назначение

Статический класс для конвертирования байтов.

Структура

Статические методы:

  • ToSize(Long) — Переводит полученное количество байт в набор гигабайт, мегабайт, килобайт и байт, представленный структурой Size.
  • ToGb(Long) — Переводит байты в гигабайты с математическим округлением.
  • ToMb(Long) — Переводит байты в мегабайты с математическим округлением.
  • ToKb(Long) — Переводит байты в килобайты с математическим округлением.

Свойства структуры Size:

  • long GByte — Количество гигабайт.
  • long MByte — Количество мегабайт.
  • long KByte — Количество килобайт.
  • long Byte — Количество оставшихся байт.

Примеры кода

var drives = DriveInfo.GetDrives();

foreach (var drive in drives)
{
    var str = new StringBuilder()
        .AppendLine("Имя диска: " + drive.Name)
        .AppendLine("Метка диска: " + drive.VolumeLabel)
        .AppendLine("Общий размер: " + Bytes.ToSize(drive.TotalSize));

    Console.WriteLine(str);
}

// Вывод:
// 
// Имя диска: C:\
// Метка диска:
// Общий размер: 100 Гбайт, 207 Мбайт, 1008 Кбайт 0 байт
// 
// Имя диска: D:\
// Метка диска: Data
// Общий размер: 171 Гбайт, 115 Мбайт, 1020 Кбайт 0 байт

Comparator

Назначение

Статический класс, который возвращает объект IComparer позволяющий сравнивать пользовательские типы по указанному параметру. Полезен при работе с Array.

Структура

Статические методы:

  • GetComparator<TSource, TKey> — Возвращает созданный объект для сравнения по переданной лямбде. Первым Generic-параметром указывается элемент коллекции, вторым возвращаемый тип данных.

Примеры кода

Array.Sort(array, Comparator.GetComparator<User, string>(p => p.Name));
// Сортировка массива объектов "User" по имени
// string - т.к. этим типом представлено свойство Name

DefaultConstants

Назначение

Дополнительные константы для примитивов.

Структура

  • string.NotEmpty — Непустая строка something.
  • int.PositiveNumber — Положительное число 1.
  • int.Zero — Содержит ноль (более явная форма default).
  • int.NegativeNumber — Отрицательное число -1.
  • int.RandomValue — Случайное число.
  • int.RandomPositiveValue — Случайное положительное число.
  • int.RandomNegativeValue — Случайное отрицательное число.
  • int.Random(int max) — Случайное число от 0 до указанного значения.
  • int.Random(int min, int max) — Случайное число в указанном диапазоне.

Примеры кода

Counter counter = new(value: int.RandomPositiveValue, name: string.NotEmpty);

IEnumerableExtensions

Назначение

Статический класс с методами расширения для перебираемых коллекций.

Структура

Методы расширения:

  • IsSorted — Проверяет отсортированность по возрастанию.
  • IsSortedDescending — Проверяет отсортированность по убыванию.
  • Have — Проверяет наличие в коллекции указанного количества элементов. Более оптимален, чем проверки с полным перебором коллекции методом Count.

Примеры кода

IsSorted:

List<int> numbers = new() { 1, 2, 3, 4, 10 };
bool isSorted = numbers.IsSorted(); // true

Have:

if (!collection.Have(2))
    return true;

ObjectExtensions

Назначение

Статический класс с методами расширения для объектов.

Структура

Методы расширения:

  • TryCast — Осуществляет попытку приведения типа, возвращая логическое значение об успехе, и записывающее сам объект в out-параметр. При необходимости вторым out-параметром возвращает сообщение об ошибке приведения типа.
  • IsNull — Проверяет значение на равенство null и возвращает результат проверки.
  • IsNotNull — Проверяет значение на не равенство null и возвращает результат проверки.

Примеры кода

TryCast:

object obj = 10;
bool isCasted = obj.TryCast(out string? str, out string? castingError);

if (!isCasted)
    Console.WriteLine(castingError); // Specified value is not a String

IsNull:

if (parameters.Any(p => p.IsNull()))
    throw new AttributeParametersException(parameters, "Attribute values cannot have null values");

StringExtensions

Назначение

Статический класс с методами расширения для строк.

Структура

Методы расширения:

  • Reduce — Сокращает строку до указанной длины, возвращая получившееся значение Message и остаток длины Remainder.
  • ReplaceWhileContain — Заменяет старое значение на новое, пока в тексте содержится старое значение (удобно для удаления повторяющихся символов).
  • TryFormat — Осуществляет попытку форматировать строку с указанными переменными, возвращая логическое значение об успешности, и саму форматированную строку при помощи out-параметра.
  • IsValidForInternalization — Проверка валидности строки на предмет интернирования указанного количества переменных.

Примеры кода

Reduce:

var result = "Очень длинная строка!".Reduce(9);
Console.WriteLine($"Получившаяся строка: {result.Message}; Остаток длины: {result.Remainder}");

// Получившаяся строка: Очень ...; Остаток длины: 0

result = "По-прежнему очень длинная строка!".Reduce(50);
Console.WriteLine($"Получившаяся строка: {result.Message}; Остаток длины: {result.Remainder}");

// Получившаяся строка: По - прежнему очень длинная строка!; Остаток длины: 17

ReplaceWhileContain:

string text = "Строка,       где очень много лишних        пробелов";
string textWithoutDoubleSpace = text.ReplaceWhileContain("  ", " ");

TryFormat:

string str = "{0} {1}";
bool isSuccessFormat = str.TryFormat(out string formatted, 10, 12);

IsValidForInternalization:

string str = "{0} {1}";
var validationResult = str.IsValidForInternalization(2);

Readyable

Назначение

Потокобезопасный объект, проверяемый на готовность. Удобен при необходимости отложено инициализировать out-параметры.

Структура

Generic-параметр:

  • TValue — Тип хранимого значения.

Свойства:

  • Name — Имя объекта.
  • Value — Значение объекта.
  • State — Состояние объекта, представленное перечислением ReadyableState:
    • NeverBeReady — Объект, который никогда не будет готов к использованию.
    • Waiting — Объект, ожидающий готовности.
    • Ready — Объект, готовый к использованию.
  • IsInitialized — Логическое значение, отражающее инициализированы ли данные.
  • IsWaiting — Логическое значение, отражающее находится ли объект в режиме ожидания.
  • IsReady — Логическое значение, отражающее готов ли объект.
  • IsNeverBeReady — Логическое значение, отражающее находится ли объект в состоянии, в котором уже никогда не будет готов.

Методы:

  • ThrowIfNotInitialized — Выбрасывает исключение, если значение объекта не инициализировано.
  • ThrowIfNotWaiting — Выбрасывает исключение, если объект не ожидает значение.
  • ThrowIfNotReady — Выбрасывает исключение, если объект не находится в состоянии готовности.
  • ToReady (Только явное использование) — Приводит объект в состояние готовности. Можно указать итоговое значение объекта.
  • ToNeverBeReady (Только явное использование) — Приводит объект в состояние, в котором он уже не будет готов никогда.

Ассоциированное с этим классом исключение ReadyableException:

  • Message — Сообщение об ошибке.
  • Name — Имя объекта, проверяемого на готовность.
  • State — Состояние объекта, связанного с ошибкой.

Соглашение об использовании:
Подразумевается, что после создание этого объекта он будет либо инициализирован и приведён в состояние готовности, либо приведён в состояние, когда он никогда не будет готов.
Если запросить его значение, когда он не находится в состоянии готовности, возникнет исключение. Как и при попытке его привести в состояние готовности, если его значение не было проинициализированно.

Примеры кода

При успешном выполнении какой-то операции, например:

// Внутри какого-то метода
((IReadyable<int>)readyable).ToReady(3); // Явное использование для небольшой защиты от лишнего вмешательства

// Где-нибудь снаружи
int value = readyable.IsReady ? readyable.Value : default;

При какой-нибудь ошибке:

if (somethingBad)
    ((IReadyable<int>)readyable).ToNeverBeReady();

Result

Назначение

Класс, хранящий сведенья о результате работы метода.

Структура

Статические методы для создания результата:

  • CreateSuccess — Создаёт сведенья об успешном результате (Есть интеграция с Readyable).
  • CreateFailure — Создаёт сведенья о невалидном результате (Есть интеграция с Readyable).

Свойства результата:

  • IsValid — Валидность результата.
  • Value — Данные валидного результата.
  • Error — Данные невалидного результата.

Обычные методы:

  • ExecuteAndExitIfNotValid — Выполняет действие над Result.Error и завершает работу приложения.

Generic-параметры:

  • TSuccess (первый параметр) — Тип данных, которым будет представлено свойство Value.
  • TFailure (второй параметр) — Тип данных, которым представлено свойство Error.

Примеры кода

Стандартное использование:

var success = Result<string, string>.CreateSuccess("Успешный успех!");
var failure = Result<string, string>.CreateFailure("Потеря потерь!");

string successMessage = success.IsValid ? success.Value : success.Error;
string failureMessage = failure.IsValid ? failure.Value : failure.Error;

Console.WriteLine(successMessage + '\n' + failureMessage);

При частом использовании одинакового набора Generic-параметров можно использовать псевдонимы:

using StringResult = san40_u5an40.ExtraLib.Broad.Result<string, string>;
var success = StringResult.CreateSuccess("Успешный успех!");

И конечно же допустимо использовать различные пользовательские типы в качестве Generic-параметров:

var success = Result<SuccessInfo, FailureInfo>.CreateSuccess(new SuccessInfo("Вася", 25));
string message =
    success.IsValid ?
    success.Value.Name + ' ' + success.Value.Age :
    success.Error.Message;
Console.WriteLine(message);

record SuccessInfo(string Name, int Age);
record FailureInfo(string Message, int ErrorCode);

ExecuteAndExitIfNotValid:

var result = Result<string, string>.CreateFailure("FAIL!!!!");
result.ExecuteAndExitIfNotValid(Console.WriteLine);

Console.WriteLine("Если бы ты не упал, ты бы жил");

// Вывод:
// FAIL!!!

Интеграция с Readyable

Методы CreateSuccess и CreateFailure имеют перегрузки со вторым Readyable параметром, который устанавливает состояние объекта в то или иное значение в зависимости от метода:

  • CreateSuccess — Инициализирует Readyable.Value своим Result.Value и устанавливает состояние Ready.
  • CreateFailure — Устанавливает состояние Readyable в NeverBeReady.

Допустимо передавать в параметр только те объекты, которые находятся в состоянии Wait. Иные попытки приведут к исключению ReadyableException.

Readyable<string> readyable = new();
Result<string,string>.CreateSuccess("Какое-то значение!", readyable);

// Теперь readyable.Value == "Какое-то значение!", а readyable.State == ReadyableState.Ready;

Chain and AsyncChain

Назначение

Классы для создания функциональных цепочек. При их запуске указанные методы начинают до конца исполняться, передавая указанные данные. Если на каком-то этапе возникнет невалидный результат, вернётся соответствующая информация об ошибке.

Примеры кода

Обычная цепочка:

var chainResult = new Chain<string[], object, string>(args)   // string[] - Тип входных данных, object - Выходных, string - Ошибка, args - Сами входные данные
    .AddMethod<string[], ArgumentsInfo>(HandleArguments)      // Получил string[],      вернул Result<ArgumentsInfo, string>
    .AddMethod<ArgumentsInfo, ContentInfo>(GetContents)       // Получил ArgumentsInfo, вернул Result<ContentInfo, string>
    .AddMethod<ContentInfo, WriterInfo>(GetOutputFileInfo)    // Получил ContentInfo,   вернул Result<WriterInfo, string>
    .AddMethod<WriterInfo, object>(WriteContents)             // Получил WriterInfo,    вернул Result<object, string>
    .Execute();                                               // Возвращает Result<object, string> (в данном случае object - заглушка)

if (!chainResult.IsValid)
{
    Console.WriteLine(chainResult.Error);
    return;
}

Console.WriteLine("Файл с оглавлением успешно создан!");

Асинхронная:

var asyncChainResult = await new AsyncChain<string, int, string>(DOCUMENT_PATH)
    .AddMethod<string, int>(GetNumberFromDocumentAsync)  // Получил string,  вернул Task<Result<int, string>>
    .AddMethod<int, int>(IncrementNumberAsync)           // Получил int,     вернул Task<Result<int, string>>
    .ExecuteAsync();

AddLoop:

new Chain<string, string, string>(string.NotEmpty)
  .AddLoop<string, string>(DoSomethingDelegate, Console.WriteLine, 5);

// Если результат будет не валиден, метод повторится, но не больше 5 раз
// Невалидный результат будет печаться в консоль, в соответствии со вторым переданным делгатом

С проектом, реализованным на базе функциональной цепочки, можно ознакомиться тут. Также более наглядный пример есть в проекте с тестами.

Структура

Создание объекта Chain и AsyncChain:

  • Generic-параметры:
    1. TInputData — Тип входных данных в цепочку.
    2. TOutputData — Тип выходных данных из цепочки.
    3. TError — Тип возвращаемой на каком-либо этапе ошибки.
  • Конструктор, где и указывают начальные данные цепочки и токен завершения (в случае AsyncChain).

Методы цепочки:

  • AddMethod — Добавляет указанные делегат в цепочку (есть поддержка Readyable out-параметра).
    1. TInput — Тип получаемых методом данных.
    2. TOutput — Тип возвращаемых методом данных в виде Result<this, Chain.TError> или Task<Result<this, Chain.TError>> при асинхронных методах.
  • AddLoop — Добавляет указанные делегат в цепочку, который при невалидном результате будет повторяться не больше заданного количества раз (также есть поддержка Readyable out-параметра).
    1. TInput — Тип получаемых методом данных.
    2. TOutput — Тип возвращаемых методом данных в виде Result<this, Chain.TError> или Task<Result<this, Chain.TError>> при асинхронных методах.
  • Execute/ExecuteAsync — Выполняет цепочку и возвращает Result<Chain.TOutputData, Chain.TError> для обычной цепочки и Result<Chain.TOutputData, InvalidAsyncChainResult<Chain.TError>>.

Подробнее про InvalidAsyncChainResult, хранимый в Result.Error у асинхронной цепочки:

  • Value? — Информация о хранимой ошибке, представлена типом Chain.TError.
  • Type — Тип невалидного результата, представленный перечислением InvalidAsyncChainResultType, имеющим следующие значения:
    • CancellationTokenRequested — Был вызван токен завершения, и его обработала цепочка (если он обрабатывается внутри метода, то тип ошибки будет другой).
    • NotValidMethodResult — Один из методов вернул невалидный результат.

Соглашения об использовании:

  • Тип входных данных первого метода цепочки и тип выходных данных последнего метода цепочки должны совпадать с типами начальных и выходных данных самой цепочки (иначе возникнет исключение).
  • Методы цепочки должны возвращать Result<TOutput, TError>, однако следующий метод принимает параметром только TOutput. Информация о валидности и сведенья об ошибке нужны для понимание самой цепочкой корректности выполнения операций.

Использование out-параметра в AddMethod

С помощью объекта Readyable можно получать промежуточные результаты, передаваемых цепочкой данных:

var incrementResult = new Chain<string, string, string>(START_VALUE)
    .AddMethod<string, int>(ConvertStringIntoInt)
    .AddMethod<int, int>(Increment, out Readyable<int> readyable)    // Сохранит промежуточный результат
    .AddMethod<int, string>(ConvertIntIntoString)
    .Execute();

Counter

Назначение

Класс, предназначенный для создания счётчиков.

Структура

Свойства:

  • Value — Значение счётчика.
  • Name — Имя счётчика.

Instance-методы:

  • Increment — Инкрементирование счётчика со стандартным или указанным шагом.
  • Decrement — Декрементирование счётчика со стандартным или указанным шагом.
  • SetValidator — Установка валидатора допустимых значений (можно лямбдой). При невалидном результате (в том числе при установке валидатора) возникнет исключение CounterNotValidValueException, которое имеет следующие свойства:
    • Counter — Счётчик, с которым связано исключение.
    • OperationType — Перечисление, хранящее операцию, которая осуществлялась со счётчиком:
      • SetValidator — Устанавливался валидатор.
      • Increment — Значение счётчика увеличивалось.
      • Decrement — Значение счётчика уменьшалось.
    • Step — Шаг, на который изменялось значение счётчика.
  • Clone — Клонирование счётчика.
  • CompareTo — Сравнение счётчиков.
  • Equals — Проверка счётчика на равенство (по значениям Name и Value).
  • GetHashCode — Переопределён для получения хеш-кода (по значениям Name и Value).
  • ToString —  Преобразование счётчика в строковое значение.

Статические методы:

  • CreateCounter — Фабрика счётчиков с указанными значениями.
  • CreateClosuredCounter — Создание счётчика на основе замыкания.

Операторы:

  • += — Увеличивает значение счётчика на указанный шаг.
  • -= — Уменьшает значение счётчика на указанный шаг.
  • ++ — Увеличивает значение счётчика на стандартный шаг.
  • -- — Уменьшает значение счётчика на стандартный шаг.
  • + double — Увеличивает значение счётчика на указанный шаг.
  • - double — Уменьшает значение счётчика на указанный шаг.
  • == — Проверка счётчика на равенство (по значениям Name и Value).
  • != — Проверка счётчика на неравенство (по значениям Name и Value).
  • > — Сравнение двух счётчиков с помощью CompareTo.
  • >= — Сравнение двух счётчиков с помощью CompareTo.
  • < — Сравнение двух счётчиков с помощью CompareTo.
  • <= — Сравнение двух счётчиков с помощью CompareTo.

Подписка на события:

  • Handler — Событие, принимающее делегат, который будет вызываться при операциях, изменяющих значение счётчика.
  • CounterEventHandler — Делегат Action<CounterOperationType, long, Counter>, принимаемый событием Handler:
    • CounterOperationType — Тип операции, производимый над счётчиком, всё те же:
      • SetValidator — Установка валидатора (но при установке валидатора событие не вызывается).
      • Increment — Увеличение значения счётчика.
      • Decrement — Уменьшение значения счётчика.
    • long — Шаг, на который изменялся счётчик.
    • Counter — Сам счётчик, связанный с событием.

Примеры кода

Со счётчиком на основе замыкания:

var cnt = Counter.CreateClosuredCounter(10);
for (int i = 0; i < 10; i++)
    Console.Write(cnt() + " ");

// 10 11 12 13 14 15 16 17 18 19

С обычным счётчиком:

Counter counter = new(value: 0, name: "Подпесчеки");
counter += 10;
counter++;
Console.WriteLine(counter); // "Подпесчеки: 11"

С подпиской на событие:

// Main:
Counter counter = new(0, "Подпесчеки");
counter.Handler += CounterEventHandler;

counter
    .Increment()
    .Increment(100)
    .Decrement()
    .Decrement(12);

// Метод-обработчик (название можно и другое):
static void CounterEventHandler(CounterOperationType type, long step, Counter counter) =>
    Console.WriteLine($"Операция: {type, -10} | Шаг: {step, - 10} | Имя счётчика: {counter.Name}");

// Вывод в консоль:
Операция: Increment  | Шаг: 1          | Имя счётчика: Подпесчеки
Операция: Increment  | Шаг: 100        | Имя счётчика: Подпесчеки
Операция: Decrement  | Шаг: 1          | Имя счётчика: Подпесчеки
Операция: Decrement  | Шаг: 12         | Имя счётчика: Подпесчеки

Verifier

Назначение

Статический класс для проверки объектов, имеющих атрибуты валидации.

Структура

Статические методы:

  • Check — Проверяет валидируемый объект и возвращает Result<T, IReadOnlyList<ValidationResult>>, где T — тип валидируемого объекта.
  • ThrowIfNotValid — Кидает исключение VerifierException, если модель не валидна, хранящее сообщения об ошибках и саму модель.

Примеры кода

Класс с атрибутами валидации:

public class User
{
    public User(string name, int age) => (Name, Age) = (name, age);

    [Required]
    [StringLength(20, MinimumLength = 3)]
    public string Name { get; private init; }

    [Required]
    [Range(18, 45)]
    public int Age { get; private init; }
}

Проверка на валидность:

//   Валидное имя - ↓     ↓ - Невалидный возраст
User user = new("Васили", 17);
var verifyResult = Verifier.Check(user);

if (!verifyResult.IsValid)
{
    foreach (var error in verifyResult.Error)
        Console.WriteLine(error.ErrorMessage); // The field Age must be between 18 and 45.
    return;
}
else
    DoSomething(user);

Custom Attributes

Назначение

Дополнительные атрибуты для валидации моделей, и шаблон их создания.

Структура

Дополнительные атрибуты:

  • ContainsAttribute — Проверяет наличие в строке указанной подстроки (поддерживает переопределение сообщения об ошибке с возможностями интернирования подстроки).
  • InternalizationSupportedAttribute — Проверяет возможность интернировать в строку количество переменных, указанных в конструкторе атрибута (поддерживает переопределение сообщения об ошибке с возможностями интернирования количества переменных).

Примеры кода

Модель с указанными атрибутами:

public class Something
{
    public Something(string maskForIntern, string textWithContainsValue) =>
        (MaskForIntern, TextWithContainsValue) = (maskForIntern, textWithContainsValue);

    [InternalizationSupported(1)] // Поддержка интернирования одной переменной в строку
    public string MaskForIntern { get; private init; }

    [Contains("TEST")]            // Содержание подстроки "TEST"
    public string TextWithContainsValue { get; private init; }
}

О методе валидации подобных моделей подробнее написано в этом разделе.

Шаблон для создания атрибутов и исключение AttributeParametersException

Абстрактный класс для создания атрибутов валидации ValidationAttributeTemplate<TAttributeTarget> требует указания в Generic-параметре типа поля, свойства или класса, валидность которого проверяется, и переопределения следующих методов:

  • private protected override (bool IsValid, string? Error) IsValidAttributeParameters() — Проверяет корректность параметров, указанных в самом атрибуте.
  • private protected override (bool IsValid, string? Error) IsValidTargetValue(TAttributeTarget) — Проверяет корректность поля, свойства или класса.

Данный класс также поддерживает переопределение стандартных сообщений об ошибках, причём и с интернированием указанных параметров. Для этого необходимо в конструктор передать сообщение об ошибке и сами параметры для интернирования. Если строка поддерживает форматирование указанного количества параметров, они будут включены в итоговое строковое значение. Если параметры не указаны, будет просто возвращена заданная строка с ошибкой. Ну а если не указана сама строка, то будет возвращена ошибка либо из IsValidTargetValue, либо стандартное значение Validation error в случае возврата null.

Если IsValidAttributeParameters вернёт false, будет выброшено исключение AttributeParametersException, которое хранит параметры, указанные в конструкторе базового класса (да, их указание требуется не только для интернирования в сообщение об ошибке).

Пример:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class ContainsAttribute : ValidationAttributeTemplate<string>
{
    private string _stringForCheckContains;

    // С помощью базового конструктора переопределяется сообщение об ошибке, интернируются указанные парметры и формируется исключение
    //                                                                                       ↓        ↓                 ↓
    public ContainsAttribute(string stringForCheckContains, string? errorMessage = null) : base(errorMessage, stringForCheckContains) =>
        _stringForCheckContains = stringForCheckContains;

    private protected override (bool IsValid, string? Error) IsValidAttributeParameters()
    {
        if (string.IsNullOrEmpty(_stringForCheckContains))
            return (false, "The string whose contents are being checked cannot be empty");
        else
            return (true, null);
    }

    private protected override (bool IsValid, string? Error) IsValidTargetValue(string validable)
    {
        if (validable.Contains(_stringForCheckContains))
            return (true, null);
        else
            return (false, $"The string should contain the \"{_stringForCheckContains}\"");
    }
}

Разделение проверки валидности на два метода необходимо для соблюдения принципа SRP, а также для корректного срабатывания исключений. Если, например, проверку параметров атрибута поставить в конструкторе этого атрибута, то исключения не будут выбрасываться, вместо этого атрибут просто не будет присваиваться, что приведёт к валидности проверяемого типа не зависимо от его значения.

EmailsParser

Назначение

Класс для работы с текстом, содержащим email-адреса.

Структура

Константы:

  • EmailRegex — Регулярное выражение, для поиска в тексте email-адресов.

Методы:

  • Replace — Меняет все email-адреса из текста на указанное значение.
  • Parse — Получение коллекции email-адресов, хранящихся в тексте.
  • IsValid — Проверяет email-адрес на валидность.

Примеры кода

Замена:

string textForFormatEmails = EmailsParser.Replace(textWithEmails, "{0}");

Получение коллекции:

List<string> emails = EmailsParser.Parse(textWithEmails);

HtmlHelper

Назначение

Вспомогательный класс, для работы с HTML-текстом.

Структура

Константы:

  • TagRegex — Регулярное выражение для поиска тегов в тексте

Методы:

  • TagsClear — Очищает строку от тегов.

Примеры кода

string html = ...;
string textFromHtmlWithoutTags = HtmlHelper.TagsClear(html);

// Пример вывода:
// Инклюзия\r\nБезопасность

ConsoleExtension

Назначение

Статический класс с блоками расширения для консоли.

Структура

Статические методы:

  • TryReadLine — Работает также как и схожие методы: записывает в out-параметр результат чтения из консоли, возвращая содержит ли этот результат символы.
  • WriteColor — Выводит в консоль текст указанного цвета без \n.
  • WriteColorLine — Выводит в консоль текст указанного цвета с \n на конце.
  • CleanLine — Очищает одну строку от текста.

Примеры кода

TryReadLine:

string result;
while(!Console.TryReadLine(out result))
    Console.WriteLine("Необходимо указать значение, повторите ввод!");

WriteColor:

internal static void PrintWelcome(string name)
{
    Console.Write("Добро пожаловать в программу, ");
    Console.WriteColor(name, ConsoleColor.Red);
    Console.Write("!\n");
}

CleanLine:

Console.Write("Текст на 3 секунды...");
Thread.Sleep(3000);
Console.CleanLine();

MessageBox

Назначение

Класс и набор перечислений, предназначенный для работы с окнами уведомлений в проектах, не подразумевающих работу на базе фреймворков графических интерфейсов.

Структура

Статический класс MessageBox:

  • Show — Метод вывода окна уведомлений. Принимает текст уведомления, заголовок окна и его тип (либо битовое поле MessageBoxType, либо объект MessageBoxOptions).

Структура битового поля и объекта с опциями схожа:

  • WindowType — Типы окон:
    • Ok — Только кнопка "Ок". (default)
    • OkCancel — Кнопки "Ок" и "Закрыть".
    • AbortRetryIgnore — Кнопки "Прервать", "Повторить" и "Пропустить".
    • YesNoCancel — Кнопки "Да", "Нет" и "Закрыть".
    • YesNo — Кнопки "Да" и "Нет".
    • RetryCancel — Кнопки "Повторить" и "Закрыть".
    • CancelTryContinue — Кнопки "Закрыть", "Повторить" и "Продолжить".
  • DefaultButton — Выбранная кнопка по умолчанию:
    • Button1 — Первая кнопка выбрана по умолчанию. (default)
    • Button2 — Соответственно.
    • Button3 — Соответственно.
    • Button4 — Соответственно.
  • IconType — Иконка окна уведомления:
    • None — Отсутствие иконки. (default)
    • Error — Красный знак ошибки.
    • Question — Знак вопроса.
    • Warning — Жёлтый знак предупреждения.
    • Information — Синий информационный знак.

Статический класс с результатами окна уведомления MessageBoxResult:

  • Ok.
  • Cancel.
  • Abort.
  • Retry.
  • Ignore.
  • Yes.
  • No.
  • Close.
  • Help.
  • Try.
  • Continue.

Примеры кода

С битовым полем:

int result = MessageBox.Show(
    "Продолжить работу программы?",
    "Окно уведомлений",
    MessageBoxType.Window_YesNoCancel | MessageBoxType.DefaultButton_2 | MessageBoxType.Icon_Question);

if (result == MessageBoxResult.Yes)
    Console.WriteLine("Я каменщик, работаем дальше...");
else if (result == MessageBoxResult.No)
    Console.WriteLine("User'а ответ!");
else
    return;

С объектом опций:

    MessageBoxOptions options = new(WindowType.OkCancel, IconType.Information, DefaultButton.Button2);
    MessageBox.Show("Это окно можно закрыть", "Информационное окно", options);

Reflection

Назначение

Статический класс, предназначенный для исследования пользовательских типов.

Структура

Атрибуты:

  • ReflectionAttribute(BindingFlags(optional)) — Атрибут для отметки класса о необходимости осуществления его рефлексивного анализа методом Reflection.Print();

Статические методы:

  • Print() — Выводит информацию о всех пользовательских типах, имеющих атрибут ReflectionAttribute (только этот метод связан с использованием атрибута);
  • Print(Type, BindingFlags(optional)) — Выводит рефлексивную информацию о переданном в параметр типе согласно указанным флагам.
  • Print(Assembly, BindingFlags(optional)) — Выводит рефлексивную информацию о переданной в параметр сборке.
  • Print(String, BindingFlags(optional)) — Выводит рефлексивную информацию о сборке, путь которой передан в параметр метода.
  • Print(String, String, BindingFlags(optional)) — Выводит рефлексивную информацию о сборке, чей путь указан, и содержащимся в ней типе, название которого указано вторым параметром.

Примеры кода

Использование через атрибут:

// Main:
Reflection.Print();

// Тестовый класс для анализа
[Reflection]
public class ClassTest
{
    private static int count = 0;
    private string? name;
    private Func<int>? getNumber;

    public string? Name => name;

    public ClassTest(string name) { }

    public ClassTest() { }

    public event Func<int> GetNumber
    {
        add
        {
            if (value == null)
                return;

            getNumber += value;
        }
        remove
        {
            if (value == null || getNumber == null)
                return;

            if (!getNumber.GetInvocationList().Contains(value))
                return;

            getNumber -= value;
        }
    }

    internal void Print(string mess, string mess2) {  }
}

// Вывод:
// Состав сборки "SandBox.dll":
//
//   Класс "ClassTest":
//   |
//   |  Поля:
//   |  |
//   |  |  Имя: name                 | Тип: System.String                            | Атрибуты: Private
//   |  |  Имя: getNumber            | Тип: System.Func`1[System.Int32]              | Атрибуты: Private
//   |  |  Имя: count                | Тип: System.Int32                             | Атрибуты: Private, Static
//   |  |
//   |  Общее количество: 3
//   |
//   |  Методы:
//   |  |
//   |  |  Имя: get_Name
//   |  |     Атрибуты: Public, HideBySig, SpecialName
//   |  |     Возвращаемый тип: System.String
//   |  |
//   |  |  Имя: add_GetNumber
//   |  |     Атрибуты: Public, HideBySig, SpecialName
//   |  |     Возвращаемый тип: Void
//   |  |     Параметры: (System.Func`1[System.Int32]) value
//   |  |
//   |  |  Имя: remove_GetNumber
//   |  |     Атрибуты: Public, HideBySig, SpecialName
//   |  |     Возвращаемый тип: Void
//   |  |     Параметры: (System.Func`1[System.Int32]) value
//   |  |
//   |  |  Имя: Print
//   |  |     Атрибуты: Assembly, HideBySig
//   |  |     Возвращаемый тип: Void
//   |  |     Параметры: (System.String) mess, (System.String) mess2
//   |  |
//   |  Общее количество: 4
//   |
//   |  Конструкторы:
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.String) name
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |
//   |  Общее количество: 2
//   |
//   Конец класса
//
// Конец сборки

Использование по ссылке на тип (поисследуем класс String):

// Main:
Reflection.Print(typeof(System.String));

// Вывод:
// Состав сборки "System.Private.CoreLib.dll":
//
//   Класс "String":
//   |
//   |  Поля:
//   |  |
//   |  |  Имя: _stringLength        | Тип: System.Int32                             | Атрибуты: Private, InitOnly, NotSerialized
//   |  |  Имя: _firstChar           | Тип: System.Char                              | Атрибуты: Private, NotSerialized
//   |  |  Имя: Empty                | Тип: System.String                            | Атрибуты: Public, Static, InitOnly
//   |  |
//   |  Общее количество: 3
//   |
//   |  Методы:
//   |  |
//   |  |  Имя: FastAllocateString
//   |  |     Атрибуты: Assembly, Static, HideBySig
//   |  |     Возвращаемый тип: System.String
//   |  |     Параметры: (System.Int32) length
//   |  |

// Тут очень много методов, можете при желании поисследовать сами

//   |  |
//   |  |  Имя: LastIndexOf
//   |  |     Атрибуты: Public, HideBySig
//   |  |     Возвращаемый тип: Int32
//   |  |     Параметры: (System.String) value, (System.Int32) startIndex, (System.Int32) count, (System.StringComparison) comparisonType
//   |  |
//   |  Общее количество: 267
//   |
//   |  Конструкторы:
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.Char[]) value
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.Char[]) value, (System.Int32) startIndex, (System.Int32) length
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.Char*) value
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.Char*) value, (System.Int32) startIndex, (System.Int32) length
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.SByte*) value
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.SByte*) value, (System.Int32) startIndex, (System.Int32) length
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.SByte*) value, (System.Int32) startIndex, (System.Int32) length, (System.Text.Encoding) enc
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.Char) c, (System.Int32) count
//   |  |
//   |  |  Имя: .ctor
//   |  |     Атрибуты: Public, HideBySig, SpecialName, RTSpecialName
//   |  |     Параметры: (System.ReadOnlySpan`1[System.Char]) value
//   |  |
//   |  Общее количество: 9
//   |
//   Конец класса
//
// Конец сборки

Использование по ссылке на сборку:

Reflection.Print(Assembly.GetAssembly(typeof(Regex)));
// Выведет все классы, входящие в состав "System.Text.RegularExpressions.dll"

Использование через указание пути сборки:

                         ↓ - экранирование знака "\"
string pathAssembly = "D:\\csharp\\projects\\ExtraLib\\bin\\Debug\\net9.0\\Text.dll";
Reflection.Print(pathAssembly);

Использование через указание пути сборки и названия класса:

                         ↓ - экранирование знака "\"
string pathAssembly = "D:\\csharp\\projects\\ExtraLib\\bin\\Debug\\net9.0\\Std.dll";

Reflection.Print(pathAssembly, "Comparator");
// Или по полному названию
Reflection.Print(pathAssembly, "Std.Comparator");

// Если полученную сборку не удастся открыть, будет выведено сообщение из Exception
// Could not load file or assembly 'D:\csharp\projects\ExtraLib\bin\Debug\net9.0\Std.dll'. Системе не удается найти указанный путь.
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on san40_u5an40.ExtraLib:

Package Downloads
san40_u5an40.ConsoleDisplayFramework

Framework for fast creation of console display

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.4.0 147 7/8/2026
5.3.0 116 7/7/2026
5.2.0 123 6/7/2026
5.1.0 125 5/15/2026
5.0.2 127 4/27/2026
5.0.1 140 2/12/2026
5.0.0 131 2/12/2026
4.4.0 132 2/9/2026
4.3.0 132 2/7/2026
4.2.0 174 2/7/2026
4.1.0 136 2/6/2026
4.0.1 129 2/5/2026
4.0.0 140 2/5/2026
3.0.0 148 1/29/2026
2.0.0 136 1/18/2026
1.3.1 138 1/15/2026
1.3.0 132 1/14/2026
1.2.0 517 12/8/2025
1.1.0 241 11/23/2025
1.0.1 441 11/19/2025
Loading failed

Улучшена потокобезопасность Counter