Anonymous Quiz
82%
List, Dictionary, Queue, Stack.
11%
Array, Hashtable, SortedList, LinkedList.
7%
Collection, Set, Map, Queue.
1%
Tree, Graph, Map, Set.
😁5
В трехслойной архитектуре (трехуровневая архитектура), также известной как многоуровневая архитектура, приложения разделяются на три логических слоя:
REST (Representational State Transfer):
С точки зрения трехслойной архитектуры:
SWAP (Simple Web API):
С точки зрения трехслойной архитектуры:
В трехслойной архитектуре REST и SWAP выступают как интерфейсы, обеспечивающие взаимодействие между слоями, при этом они сами чаще всего принадлежат к логическому слою, поскольку реализуют бизнес-логику и правила приложения, обеспечивая доступ к данным через слой данных и предоставляя функционал презентационному слою.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Anonymous Quiz
98%
async, await.
1%
parallel, concurrent.
0%
thread, lock.
1%
task, event.
🤯4
Паттерны Adapter и Decorator оба являются структурными паттернами, которые помогают управлять взаимодействием между объектами. Однако, они решают разные задачи и применяются в различных контекстах. Рассмотрим каждый из этих паттернов подробнее и сравним их.
Описание:
Цель:
Применение:
Пример:
// Существующий класс с несовместимым интерфейсом
public class LegacyPrinter
{
public void PrintLegacy(string text)
{
Console.WriteLine("Legacy print: " + text);
}
}
// Целевой интерфейс, который ожидает клиент
public interface IPrinter
{
void Print(string text);
}
// Адаптер, который приводит интерфейс LegacyPrinter к интерфейсу IPrinter
public class PrinterAdapter : IPrinter
{
private readonly LegacyPrinter _legacyPrinter;
public PrinterAdapter(LegacyPrinter legacyPrinter)
{
_legacyPrinter = legacyPrinter;
}
public void Print(string text)
{
_legacyPrinter.PrintLegacy(text);
}
}
// Использование адаптера
public class Client
{
public void ClientCode(IPrinter printer)
{
printer.Print("Hello, World!");
}
}
var legacyPrinter = new LegacyPrinter();
var adapter = new PrinterAdapter(legacyPrinter);
var client = new Client();
client.ClientCode(adapter);
Описание:
Цель:
Пример:
// Базовый интерфейс
public interface INotifier
{
void Send(string message);
}
// Конкретный компонент
public class EmailNotifier : INotifier
{
public void Send(string message)
{
Console.WriteLine("Sending Email: " + message);
}
}
// Базовый декоратор
public class NotifierDecorator : INotifier
{
private readonly INotifier _wrappee;
public NotifierDecorator(INotifier notifier)
{
_wrappee = notifier;
}
public virtual void Send(string message)
{
_wrappee.Send(message);
}
}
// Конкретный декоратор
public class SMSNotifier : NotifierDecorator
{
public SMSNotifier(INotifier notifier) : base(notifier) { }
public override void Send(string message)
{
base.Send(message);
Console.WriteLine("Sending SMS: " + message);
}
}
// Использование декоратора
var emailNotifier = new EmailNotifier();
var smsNotifier = new SMSNotifier(emailNotifier);
smsNotifier.Send("Hello, World!");
Паттерн Adapter преобразует интерфейс одного класса к интерфейсу, ожидаемому клиентом, что позволяет несовместимым объектам работать вместе. Паттерн Decorator динамически добавляет новые обязанности объекту, оборачивая его, и предоставляет гибкую альтернативу наследованию для расширения функциональности. Adapter используется для приведения интерфейсов в соответствие, а Decorator — для расширения возможностей объектов.
Please open Telegram to view this post
VIEW IN TELEGRAM
Anonymous Quiz
97%
DateTime, TimeSpan.
1%
Calendar, Clock.
2%
Timestamp, Stopwatch.
0%
Period, Interval.
👍1🤔1
Паттерн проектирования Factory (Фабрика) — это порождающий паттерн, который предоставляет интерфейс для создания объектов в суперклассе, но позволяет подклассам изменять тип создаваемых объектов. Основная идея заключается в том, чтобы вынести создание объектов из кода, который их использует, в отдельный компонент или метод. Это помогает уменьшить зависимость кода от конкретных классов и улучшить его гибкость и расширяемость.
public class SimpleFactory
{
public IProduct CreateProduct(string type)
{
if (type == "A")
return new ProductA();
else if (type == "B")
return new ProductB();
else
throw new ArgumentException("Unknown product type.");
}
}
public abstract class Creator
{
public abstract IProduct FactoryMethod();
}
public class ConcreteCreatorA : Creator
{
public override IProduct FactoryMethod()
{
return new ProductA();
}
}
public class ConcreteCreatorB : Creator
{
public override IProduct FactoryMethod()
{
return new ProductB();
}
}
Паттерн Factory позволяет абстрагировать процесс создания объектов, уменьшая зависимость от конкретных классов и улучшая гибкость и расширяемость кода. Он включает такие разновидности, как простая фабрика, фабричный метод и абстрактная фабрика, каждая из которых решает свои специфические задачи по созданию объектов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Anonymous Quiz
86%
Преобразование объектов в поток байтов и обратно.
5%
Сжатие данных и их восстановление.
6%
Шифрование и дешифрование данных.
4%
Конвертация строк в числа и обратно.
В современном C# паттерн Singleton можно реализовать несколькими способами, каждый из которых имеет свои преимущества и предназначен для различных сценариев использования. Рассмотрим несколько распространенных подходов к реализации Singleton.
Ленивый Singleton инициализируется при первом обращении. Это обеспечивает отложенную инициализацию объекта и гарантирует потокобезопасность.
Пример:
public class Singleton
{
private static readonly Lazy<Singleton> lazyInstance = new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance => lazyInstance.Value;
private Singleton()
{
// Приватный конструктор
}
}
Lazy<T> позволяет легко и безопасно реализовать отложенную инициализацию.Этот подход использует
lock для обеспечения потокобезопасности при создании экземпляра.Пример:
public class Singleton
{
private static Singleton instance;
private static readonly object lockObj = new object();
private Singleton()
{
// Приватный конструктор
}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (lockObj)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
lock, проверяя instance дважды.Экземпляр Singleton создается при загрузке класса. Это гарантирует потокобезопасность за счет особенностей инициализации статических переменных в .NET.
Пример:
public class Singleton
{
private static readonly Singleton instance = new Singleton();
public static Singleton Instance => instance;
private Singleton()
{
// Приватный конструктор
}
}
Использование статического конструктора для инициализации Singleton.
Пример:
public class Singleton
{
private static readonly Singleton instance;
static Singleton()
{
instance = new Singleton();
}
public static Singleton Instance => instance;
private Singleton()
{
// Приватный конструктор
}
}
В современных приложениях, особенно с использованием ASP.NET Core, Singleton часто регистрируется в контейнере внедрения зависимостей.
Пример:
public class SingletonService
{
public void DoWork()
{
// Выполнение работы
}
}
// Регистрация в контейнере служб
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<SingletonService>();
}
// Использование в контроллере
public class MyController : ControllerBase
{
private readonly SingletonService _singletonService;
public MyController(SingletonService singletonService)
{
_singletonService = singletonService;
}
public IActionResult Index()
{
_singletonService.DoWork();
return Ok();
}
}
В C# паттерн Singleton реализуется с использованием различных подходов: ленивой инициализации (с
Lazy<T>), потокобезопасного двойного блокирования, инициализации при загрузке класса и статического конструктора. В современных приложениях также используется внедрение зависимостей (DI), особенно в ASP.NET Core, для обеспечения единственного экземпляра.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2
Anonymous Quiz
99%
Блоками try, catch, finally.
1%
Методами include, require.
1%
Операторами check, uncheck.
0%
Командами start, end.
❤1
public class BaseClass
{
public virtual void DoWork() { /* базовое поведение */ }
}
public class DerivedClass : BaseClass
{
public override void DoWork() { /* расширенное поведение */ }
}
public interface IWork
{
void DoWork();
}
public class MyClass : IWork
{
public void DoWork() { /* реализация интерфейса */ }
}
public class BaseClass
{
public virtual void DoWork() { /* базовое поведение */ }
}
public class Decorator : BaseClass
{
private BaseClass _base;
public Decorator(BaseClass baseClass) { _base = baseClass; }
public override void DoWork()
{
_base.DoWork();
// Добавленное поведение
}
}
public interface ITarget
{
void Request();
}
public class Adaptee
{
public void SpecificRequest() { /* специальное поведение */ }
}
public class Adapter : ITarget
{
private Adaptee _adaptee = new Adaptee();
public void Request() { _adaptee.SpecificRequest(); }
}
public static class Extensions
{
public static void NewMethod(this ExistingClass obj)
{
// Добавленное поведение
}
}
Поведение классов в C# можно расширить через наследование, интерфейсы, паттерн декоратор, адаптер и расширяющие методы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
👾 466 вопросов собесов на С# Developer
🔒 База реальных собесов
🔒 База тестовых заданий
👾 Список менторов
👩💻 С#
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 Kotlin
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 Swift
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👣 Golang
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 С/С++
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 PHP
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
🖥 Frontend
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
🖥 Тестировщик
├ Вопросы собесов
├ Вакансии
└ Тесты
🖥 Python
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 Java
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
🖥 Data Science
├ Вопросы собесов
├ Вакансии
└ Тесты
👩💻 DevOps
├ Вопросы собесов
├ Вакансии
└ Тесты
⚙ Backend
└ Вопросы собесов
👾 Список менторов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
└ Тесты
├ Вопросы собесов
├ Вакансии
└ Тесты
└ Вопросы собесов
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2🔥1
Anonymous Quiz
95%
Метаданные для классов и методов.
3%
Методы для логирования.
1%
Инструменты для отладки.
1%
Операции над массивами.
🤯3👍1
В C# вы можете изменить поведение методов в классе-наследнике при соблюдении определенных условий. Рассмотрим основные способы изменения поведения методов в наследуемых классах.
Если метод базового класса объявлен с ключевым словом
virtual, его можно переопределить в классе-наследнике с использованием ключевого слова override.public class BaseClass
{
public virtual void DoWork()
{
Console.WriteLine("BaseClass DoWork");
}
}
public class DerivedClass : BaseClass
{
public override void DoWork()
{
Console.WriteLine("DerivedClass DoWork");
}
}
class Program
{
static void Main()
{
BaseClass obj = new DerivedClass();
obj.DoWork(); // Выведет: "DerivedClass DoWork"
}
}
Если метод базового класса не объявлен с ключевым словом
virtual, вы можете скрыть его в классе-наследнике с использованием ключевого слова new. Однако, это не является переопределением в строгом смысле, и поведение метода будет зависеть от типа ссылки на объект.public class BaseClass
{
public void DoWork()
{
Console.WriteLine("BaseClass DoWork");
}
}
public class DerivedClass : BaseClass
{
public new void DoWork()
{
Console.WriteLine("DerivedClass DoWork");
}
}
class Program
{
static void Main()
{
BaseClass objBase = new BaseClass();
objBase.DoWork(); // Выведет: "BaseClass DoWork"
DerivedClass objDerived = new DerivedClass();
objDerived.DoWork(); // Выведет: "DerivedClass DoWork"
BaseClass objPolymorphic = new DerivedClass();
objPolymorphic.DoWork(); // Выведет: "BaseClass DoWork"
}
}
Вы можете изменить или дополнить поведение, реализуя интерфейсы в классе-наследнике.
public interface IWork
{
void DoWork();
}
public class BaseClass : IWork
{
public virtual void DoWork()
{
Console.WriteLine("BaseClass DoWork");
}
}
public class DerivedClass : BaseClass
{
public override void DoWork()
{
Console.WriteLine("DerivedClass DoWork");
}
}
class Program
{
static void Main()
{
IWork obj = new DerivedClass();
obj.DoWork(); // Выведет: "DerivedClass DoWork"
}
}
В C# вы можете изменить поведение методов в классе-наследнике, если метод базового класса объявлен как
virtual. В этом случае вы можете переопределить его с использованием override. Для методов, не объявленных как virtual, можно использовать сокрытие (new), но это не даст полиморфного поведения.Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
Anonymous Quiz
99%
public, private, protected, internal, protected internal.
0%
open, closed, abstract, final.
1%
internal, external, global, local.
0%
static, dynamic, final, transient.
❤1
Наследование — одна из ключевых концепций объектно-ориентированного программирования (ООП). Оно позволяет создавать новые классы на основе уже существующих, используя их свойства и методы, и при этом добавлять новые или изменять существующие.
public class Animal
{
public string Name { get; set; }
public void Eat()
{
Console.WriteLine("Eating...");
}
public virtual void MakeSound()
{
Console.WriteLine("Some generic animal sound");
}
}
public class Dog : Animal
{
public void Bark()
{
Console.WriteLine("Woof!");
}
public override void MakeSound()
{
Console.WriteLine("Bark");
}
}
class Program
{
static void Main()
{
Dog myDog = new Dog();
myDog.Name = "Buddy";
myDog.Eat(); // Наследованный метод
myDog.Bark(); // Метод производного класса
myDog.MakeSound(); // Переопределенный метод
}
}
Name и метод Eat.MakeSound объявлен как virtual, что позволяет его переопределить в производных классах.Animal.Bark.MakeSound с использованием ключевого слова override.Dog может использовать как унаследованные методы (Eat), так и методы, определенные в классе Dog (Bark).MakeSound заменяет версию из базового класса Animal.Наследование позволяет реализовать полиморфизм, который позволяет обрабатывать объекты производных классов через ссылки на базовый класс.
public class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine("Meow");
}
}
class Program
{
static void Main()
{
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.MakeSound(); // Выведет: Bark
myCat.MakeSound(); // Выведет: Meow
}
}
Наследование в ООП позволяет создавать новые классы на основе существующих, используя их свойства и методы, и при этом добавляя или изменяя поведение. Это способствует повторному использованию кода, расширяемости и поддержке полиморфизма, позволяя обрабатывать объекты разных типов через единый интерфейс.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
В C#
const, readonly и static используются для разных целей и имеют разные характеристики. Давайте рассмотрим различия между ними.const, является константой и должно быть инициализировано во время объявления. Значение const поля не может быть изменено после компиляции.const поддерживает только примитивные типы данных, строки и enum.public class MyClass
{
public const int MyConst = 10;
}
readonly, может быть инициализировано либо во время объявления, либо в конструкторе. Значение readonly поля может быть изменено только в конструкторе и не может быть изменено после этого.readonly поля используются для значений, которые должны быть неизменными после инициализации объекта, но могут различаться между экземплярами класса.readonly поддерживает любые типы данных.public class MyClass
{
public readonly int MyReadonly;
public MyClass(int value)
{
MyReadonly = value;
}
}
static, принадлежит классу, а не конкретному экземпляру. Оно является общим для всех экземпляров класса и хранится в одной области памяти.static поля используются для значений, которые должны быть общими для всех экземпляров класса. Они могут быть изменены в любой момент времени.static поддерживает любые типы данных.public class MyClass
{
public static int MyStatic;
static MyClass()
{
MyStatic = 10;
}
}
| Характеристика |
const | readonly | static ||--------------------|----------------------------------|------------------------------------|------------------------------------|
| Инициализация | Во время объявления | Во время объявления или в конструкторе | В статическом конструкторе или во время объявления |
| Изменение | Нельзя изменять после компиляции | Можно изменять только в конструкторе | Можно изменять в любом месте кода |
| Область действия | Локальная для класса или метода | Локальная для экземпляра | Общая для всех экземпляров |
| Тип данных | Примитивные, строки,
enum | Любые типы данных | Любые типы данных |const: Неизменяемая константа, инициализируется при объявлении, не может быть изменена.readonly: Неизменяемое поле после инициализации в конструкторе, поддерживает любые типы данных.static: Поле, общее для всех экземпляров класса, может быть изменено в любое время.Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Anonymous Quiz
97%
Механизм передачи методов как параметров и система обратных вызовов.
1%
Средства для логирования.
1%
Интерфейсы для взаимодействия с базами данных.
0%
Операции над строками.
😁7
.NET Core и .NET Framework — это две различные реализации платформы .NET, и между ними есть несколько ключевых различий:
// Пример консольного приложения на .NET Core
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, .NET Core!");
}
}
// Пример консольного приложения на .NET Framework
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, .NET Framework!");
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤1
Anonymous Quiz
99%
Асинхронные методы для улучшения производительности.
0%
Команды для отладки.
1%
Атрибуты для сериализации.
0%
Методы для работы с массивами.
😁8
Паттерн Медиатор (Mediator) относится к поведенческим паттернам проектирования и предназначен для уменьшения зависимости между объектами, что облегчает их взаимодействие и повышает их повторное использование. Медиатор инкапсулирует способ взаимодействия множества объектов, предотвращая их прямое взаимодействие и вместо этого направляя взаимодействие через центральный объект — медиатор.
Рассмотрим пример чата, где различные компоненты (пользователи) общаются друг с другом через медиатор (чат-комнату).
public interface IChatRoomMediator
{
void ShowMessage(User user, string message);
}
public class ChatRoom : IChatRoomMediator
{
public void ShowMessage(User user, string message)
{
string time = DateTime.Now.ToString("HH:mm");
string sender = user.Name;
Console.WriteLine($"{time} [{sender}]: {message}");
}
}
public class User
{
private IChatRoomMediator _chatRoom;
public string Name { get; private set; }
public User(IChatRoomMediator chatRoom, string name)
{
_chatRoom = chatRoom;
Name = name;
}
public void Send(string message)
{
_chatRoom.ShowMessage(this, message);
}
}
class Program
{
static void Main(string[] args)
{
IChatRoomMediator chatRoom = new ChatRoom();
User user1 = new User(chatRoom, "Alice");
User user2 = new User(chatRoom, "Bob");
user1.Send("Hello, Bob!");
user2.Send("Hi, Alice!");
}
}
Паттерн Медиатор централизует взаимодействие между объектами, снижая их взаимозависимость. Объекты взаимодействуют через медиатор, который координирует их работу, упрощая структуру и повышая гибкость системы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥6
Anonymous Quiz
89%
Использование ключевого слова var.
2%
Использование ключевого слова auto.
8%
Использование ключевого слова dynamic.
1%
Использование ключевого слова implicit.
😁3👍1