C#Hive: Projects & Progress | Программирование

Логотип телеграм канала @csharphive — C#Hive: Projects & Progress | Программирование C
Актуальные темы из канала:
Lvl
Задача
Hive
Полезно
Решение
Trycatch
Exception
Pattern
Dependencyinjection
All tags
Логотип телеграм канала @csharphive — C#Hive: Projects & Progress | Программирование
Актуальные темы из канала:
Lvl
Задача
Hive
Полезно
Решение
Trycatch
Exception
Pattern
Dependencyinjection
All tags
Адрес канала: @csharphive
Категории: Технологии
Язык: Русский
Количество подписчиков: 1.80K
Описание канала:

Сообщество единомышленников C#: решаем задачи, учимся, развиваемся и общаемся вместе. Советы по работе на фрилансе, готовые проекты, код ревью, рекомендации и исследования.
Вопросы/сотрудничество: @tel_phil9

Рейтинги и Отзывы

4.00

3 отзыва

Оценить канал csharphive и оставить отзыв — могут только зарегестрированные пользователи. Все отзывы проходят модерацию.

5 звезд

2

4 звезд

0

3 звезд

0

2 звезд

1

1 звезд

0


Последние сообщения

11 окт 2025
Функциональное внедрение через Ambient Context

Продолжаем разбор прошлой темы.

Можно выделить три способа для внедрения зависимости в объект:
1. Constructor Injection. Зависимости передаются классу через его конструктор;
2. Property Injection. Зависимости передаются классу через публичные свойства после создания объекта. Способ предоставляет необязательные зависимости и позволяет менять их во время выполнения без создания новых экземпляров;
3. Method Injection. Зависимость вводится в метод, который будет её использовать.

Идея же Ambient Context заключается в создании публичного статического свойства или метода, предоставляющих экземпляр объекта определённого типа и доступного любому объекту в приложении. Паттерн позволяет предоставлять зависимости функциям, не передавая их явно в качестве параметров. Он особенно полезен для обработки сквозных задач в функциональном стиле.

Предположим, у нас есть класс логирования со следующей функцией:
public static class Logger
{
public static void Print(string message)
{
string data = $"[{DateTime.Now}] {message}";
Console.WriteLine(data);
}
}

Представим, что мы хотим иметь возможность изменять способ логирования (например, записывать в файл) без изменения сигнатуры функции Print. Решить такую задачу можно примерно следующим кодом:
public static class Logger
{
public static Action PrintHandler { set => _printHandler = value; }

static Logger() => sync = new();

private static Action _printHandler;
private static readonly object sync;

public static void Print(string message)
{
lock (sync)
{
string data = $"[{DateTime.Now}] {message}";

(_printHandler ?? Console.WriteLine)(data);
}
}
}

Используем:
Logger.PrintHandler = (msg) => File.AppendAllText("Log.txt", $"{msg}\r\n");
Logger.Print("This message will be written to file!");

Logger.PrintHandler = null;
Logger.Print("This message will be printed to console!");

Добавив делегат PrintHandler, отвечающий за сквозную реализацию, любой источник извне может корректировать реализацию метода Print. Если обработчик не трогать, то класс по умолчанию выведет сообщение в консоль. Первое сообщение логируется в файл, второе же будет выведено в консоль.

Гибкость и расширяемость такого способа ясна, а подмена зависимости для тестов сильно упростит тестирование. Однако есть и минусы: сложность в отслеживании реализации зависимости, понимание кода может быть затруднено и необходимо аккуратно управлять контекстом из-за непредсказуемого поведения.

#Полезно #DependencyInjection #Паттерн
464 views04:59
Подробнее
Поделиться:
Открыть/Комментировать
9 окт 2025
Решение задачи к посту.

int MajorityElement(int[] items)
{
var hashtable = new Hashtable();

for (int i = 0; i < items.Length; i++)
{
int item = items[i];
hashtable[item] = hashtable.ContainsKey(item) ? (int)hashtable[item] + 1 : hashtable[item] = 1;
if ((int)hashtable[item] > items.Length / 2) return item;
}

return -1;
}

#Задача #Решение #Полезно
400 views14:59
Подробнее
Поделиться:
Открыть/Комментировать
9 окт 2025
Задача: алгоритм большинства голосов ( )

Написать метод, который принимает массив размером N, находит мажорирующий элемент (который встречается более N/2 раз) и возвращает его. Допускается только один проход по массиву, чтобы определить элемент большинства. Ниже приведены примеры.

int[] array = { 2, 12, 2, 2, 2, 4, 2 };
MajorityElement(array);
2

int[] array = { 3, 3, 4, 2, 4, 4, 2, 4, 4 };
MajorityElement(array);
4

int[] array = { 5, 5, 7, 7, 9, 9 };
MajorityElement(array);
-1

int[] array = { 4, 3, 4 };
MajorityElement(array);
4

int[] array = { 1, 1, 1, 1, 1, 1 };
MajorityElement(array);
1

Пишите варианты в комментариях. Решение будет сегодня вечером новым постом в канале.

#Задача #Lvl1
419 views04:59
Подробнее
Поделиться:
Открыть/Комментировать
23 сен 2025
Решение задачи к посту.

int BinaryGCD(int a, int b)
{
int k = 1;

while (a != 0 && b != 0)
{
while (a % 2 == 0 && b % 2 == 0)
{
a /= 2;
b /= 2;
k *= 2;
}

while (a % 2 == 0) a /= 2;
while (b % 2 == 0) b /= 2;

if (a >= b) a -= b;
else b -= a;
}

return b * k;
}

#Задача #Решение #Полезно
545 views15:03
Подробнее
Поделиться:
Открыть/Комментировать
23 сен 2025
Задача: бинарный алгоритм вычисления НОД ( )

Написать метод, который реализует нахождение наибольшего общего делителя (НОД) между двумя значениями, используя бинарный алгоритм, и возвращает результат. Ниже приведены примеры.

BinaryGCD(a: 24, b: 18);
6

BinaryGCD(223744, 300181);
19

BinaryGCD(148764, 10308);
12

BinaryGCD(808, 1212);
404

BinaryGCD(111, 17);
1

Пишите варианты в комментариях. Решение будет сегодня вечером новым постом в канале.

#Задача #Lvl1
513 views05:03
Подробнее
Поделиться:
Открыть/Комментировать
13 сен 2025
Ключевые слова checked и unchecked

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

Допускается указывать, будет ли в коде генерироваться исключение при переполнении, с помощью ключевых слов checked и unchecked. Так, если требуется указать, что выражение будет проверяться на переполнение, следует использовать ключевое слово checked, а если требуется проигнорировать переполнение — ключевое слово unchecked. В последнем случае результат усекается, чтобы не выйти за пределы диапазона представления чисел для целевого типа выражения.

У ключевого слова checked имеются две общие формы. В одной форме проверяется конкретное выражение, поэтому она называется операторной. В другой форме проверяется блок операторов, поэтому она называется блочной. Ниже приведены обе формы:
checked(выражение)

checked
{
// Проверяемые операторы
// ...
}

Если вычисление проверяемого выражения или блока приводит к переполнению, то генерируется исключение OverflowException.

У ключевого слова unchecked также имеются две общие формы. Их синтаксис имеет ту же основу:
unchecked(выражение)

unchecked
{
// Операторы, для которых переполнение игнорируется
// ...
}

Если же в непроверяемом выражении или блоке происходит переполнение, то результат его вычисления усекается.

Используем unchecked в одном выражении:
int maxInt = int.MaxValue;
int uncheckedResult = unchecked(maxInt + 1);
Console.WriteLine(uncheckedResult);

Вывод с урезанным результатом:
-2147483648

Используем checked для всего блока операторов:
checked
{
try
{
int maxInt = int.MaxValue;
int checkedResult = maxInt + 1;
Console.WriteLine(checkedResult);
}
catch (OverflowException e)
{
Console.WriteLine($"Переполнение: {e.Message}");
}
}

Вывод:
Переполнение: Arithmetic operation resulted in an overflow.

Использовать checked уместно там, где переполнение может привести к критическим ошибкам в логике нашего приложения.

#Полезно #Exception #TryCatch
654 views04:59
Подробнее
Поделиться:
Открыть/Комментировать
7 сен 2025
Решение задачи к посту.

public class KnapsackProblem
{
public Item[] Items { get; }
public int MaxWeight { get; }
public Backpack BestBackpack { get; }

private KnapsackProblem(Item[] items, int maxWeight)
{
Items = items;
MaxWeight = maxWeight;
BestBackpack = GetBestBackpack();
}

public static KnapsackProblem Solve(Item[] items, int maxWeight)
{
if (items == null) throw new ArgumentNullException(nameof(items));
if (items.Length < 1) throw new ArgumentOutOfRangeException(nameof(items));
if (maxWeight < 0) throw new ArgumentOutOfRangeException(nameof(maxWeight));

return new(items, maxWeight);
}

public override string ToString() => $"Наибольшая ценность при весе {BestBackpack.Items.Sum(x => x.Weight)} кг: {BestBackpack}";

private Backpack GetBestBackpack()
{
int rows = Items.Length + 1;
int columns = MaxWeight + 1;
var backpacks = BackpackOptions(rows, columns);

return backpacks[rows - 1, columns - 1];
}

private Backpack[,] BackpackOptions(int rows, int columns)
{
Backpack[,] backpacks = new Backpack[rows, columns];

for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
if (i == 0 || j == 0)
{
backpacks[i, j] = new();
continue;
}

var item = Items[i - 1];
if (i == 1)
{
backpacks[i, j] = item.Weight <= j ? new(item) : new();
continue;
}

var prevBackpack = backpacks[i - 1, j];
if (item.Weight > j)
{
backpacks[i, j] = prevBackpack;
continue;
}

int budget = item.Price + backpacks[i - 1, j - item.Weight].Budget;
if (prevBackpack.Budget > budget)
{
backpacks[i, j] = prevBackpack;
continue;
}

Backpack backpack = new(item);
backpacks[i - 1, j - item.Weight].Items.ForEach(x => backpack.AddItem(x));
backpacks[i, j] = backpack;
}
}

return backpacks;
}
}

#Задача #Решение #Полезно
475 views14:59
Подробнее
Поделиться:
Открыть/Комментировать
7 сен 2025
Задача: проблема рюкзака ( )

Дано два класса:
public class Item
{
public string Name { get; }
public int Weight { get; }
public int Price { get; }

public Item(string name, int weight, int price)
{
Name = string.IsNullOrWhiteSpace(name) ? throw new ArgumentNullException(nameof(name)) : name;
Weight = weight < 0 ? throw new ArgumentOutOfRangeException(nameof(weight)) : weight;
Price = price < 0 ? throw new ArgumentOutOfRangeException(nameof(price)) : price;
}

public override string ToString() => Name;
}

public class Backpack
{
public int Budget { get; private set; }
public List Items { get; }

public Backpack() => Items = new();
public Backpack(Item item)
{
Items = new();
AddItem(item);
}

public override string ToString() => Items.Count == 0
? Budget.ToString()
: $"{Budget} = {string.Join(" + ", Items.Select(x => x.Name))}";

public void AddItem(Item item)
{
Items.Add(item ?? throw new ArgumentNullException(nameof(item)));
Budget += item.Price;
}
}

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

Item[] items =
{
new("Ноутбук", 3, 2000),
new("Гитара", 1, 1500),
new("Бензопила", 4, 3000)
};

KnapsackProblem knapsackProblem = KnapsackProblem.Solve(items, maxWeight: 4);
Console.WriteLine(knapsackProblem);
Наибольшая ценность при весе 4 кг: 3500 = Гитара + Ноутбук

Item[] items =
{
new("Ноутбук", 2, 40000),
new("Книга", 1, 600),
new("Бинокль", 2, 5000),
new("Аптечка", 4, 1500),
new("Котелок", 1, 500)
};
int maxWeight = 8;

KnapsackProblem kp = KnapsackProblem.Solve(items, maxWeight);
Backpack backpack = kp.BestBackpack;
Console.WriteLine(backpack);
46500 = Аптечка + Бинокль + Ноутбук

Item[] items =
{
new("1", 5, 3),
new("2", 10, 5),
new("3", 6, 4),
new("4", 5, 2)
};

KnapsackProblem knapsackProblem = KnapsackProblem.Solve(items, 14);
Console.WriteLine(knapsackProblem);
Наибольшая ценность при весе 11 кг: 7 = 3 + 1

Пишите варианты в комментариях. Решение будет сегодня вечером новым постом в канале.

#Задача #Lvl2
472 views04:59
Подробнее
Поделиться:
Открыть/Комментировать