В современном 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
Использование контейнеров, таких как Docker, в .NET приложениях имеет множество преимуществ, но также и некоторые недостатки. Вот основные из них:
Преимущества использования Docker для .NET приложений включают портативность, изолированность, легкость масштабирования, быстрое развертывание, консистентность среды и упрощенную CI/CD. Недостатки включают сложность изучения, потенциальные накладные расходы на производительность, вопросы безопасности, ограничения хост-системы и сложности управления состоянием и данными.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1
Anonymous Quiz
77%
Интерфейсы не могут содержать реализацию методов, абстрактные классы могут.
17%
Абстрактные классы могут содержать только абстрактные методы.
2%
Интерфейсы могут содержать поля.
5%
Абстрактные классы не могут быть наследованы.
🤔5👾1
Атрибуты в C# — это специальные метаданные, которые могут быть добавлены к кодовым элементам (классам, методам, свойствам, полям и т.д.) для предоставления дополнительной информации о них. Эти метаданные могут быть использованы во время выполнения программы с помощью рефлексии для изменения поведения или конфигурации приложения.
Атрибуты объявляются путем создания классов, производных от
System.Attribute. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyCustomAttribute : Attribute
{
public string Description { get; }
public MyCustomAttribute(string description)
{
Description = description;
}
}
Атрибуты применяются путем указания их над соответствующими кодовыми элементами.
[MyCustomAttribute("This is a sample class")]
public class SampleClass
{
[MyCustomAttribute("This is a sample method")]
public void SampleMethod()
{
// Метод
}
}Рефлексия используется для получения информации об атрибутах во время выполнения.
using System;
using System.Reflection;
class Program
{
static void Main()
{
Type type = typeof(SampleClass);
// Получение атрибутов класса
object[] classAttributes = type.GetCustomAttributes(false);
foreach (var attr in classAttributes)
{
MyCustomAttribute myAttr = attr as MyCustomAttribute;
if (myAttr != null)
{
Console.WriteLine($"Class Attribute: {myAttr.Description}");
}
}
// Получение атрибутов метода
MethodInfo method = type.GetMethod("SampleMethod");
object[] methodAttributes = method.GetCustomAttributes(false);
foreach (var attr in methodAttributes)
{
MyCustomAttribute myAttr = attr as MyCustomAttribute;
if (myAttr != null)
{
Console.WriteLine($"Method Attribute: {myAttr.Description}");
}
}
}
}
C# и .NET Framework включают множество встроенных атрибутов для различных целей:
[Obsolete]: Указывает, что элемент устарел. [Obsolete("This method is obsolete. Use NewMethod instead.")]
public void OldMethod() { }
[Serializable]: Указывает, что класс может быть сериализован. [Serializable]
public class MySerializableClass { }
[TestMethod]: Используется в тестовых фреймворках, таких как MSTest, для обозначения метода тестирования. [TestMethod]
public void TestMethod1() { }
[HttpGet], [HttpPost]: Указывают, какие HTTP методы поддерживает контроллер в ASP.NET. [HttpGet]
public IActionResult Get() { }
Атрибуты в C# — это метаданные, добавляемые к кодовым элементам для предоставления дополнительной информации, конфигурации, валидации и интеграции с внешними инструментами. Они объявляются как классы, производные от
System.Attribute, и используются с помощью рефлексии для изменения поведения программы во время выполнения.Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Anonymous Quiz
88%
Единица развертывания и версияции кода.
6%
Компонент для отладки кода.
3%
Объект для работы с потоками.
3%
Метод для сериализации данных.
Рефлексия (Reflection) в C# — это механизм, который позволяет программам исследовать и изменять свою структуру и поведение во время выполнения. С помощью рефлексии можно получать информацию о сборках, модулях, типах, методах, свойствах и других элементах кода, а также динамически вызывать методы и создавать экземпляры типов.
using System;
using System.Reflection;
public class ExampleClass
{
public int ExampleProperty { get; set; }
public void ExampleMethod()
{
Console.WriteLine("Hello from ExampleMethod!");
}
}
class Program
{
static void Main()
{
Type type = typeof(ExampleClass);
// Получение информации о свойствах
PropertyInfo[] properties = type.GetProperties();
foreach (var property in properties)
{
Console.WriteLine($"Property: {property.Name}, Type: {property.PropertyType}");
}
// Получение информации о методах
MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
{
Console.WriteLine($"Method: {method.Name}");
}
}
}
using System;
public class ExampleClass
{
public void ExampleMethod()
{
Console.WriteLine("Hello from ExampleMethod!");
}
}
class Program
{
static void Main()
{
Type type = typeof(ExampleClass);
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("ExampleMethod");
method.Invoke(instance, null); // Вывод: "Hello from ExampleMethod!"
}
}
using System;
using System.Reflection;
public class ExampleClass
{
public void Greet(string name)
{
Console.WriteLine($"Hello, {name}!");
}
}
class Program
{
static void Main()
{
Type type = typeof(ExampleClass);
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("Greet");
method.Invoke(instance, new object[] { "World" }); // Вывод: "Hello, World!"
}
}
Рефлексия в C# — это механизм для динамического исследования и изменения структуры и поведения программы во время выполнения. Она используется для получения информации о типах, создания объектов, вызова методов и других целей, таких как создание плагинов, сериализация, тестирование и отладка.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🤯1
Anonymous Quiz
70%
Возвращает первый не-null операнд.
13%
Возвращает последний не-null операнд.
16%
Используется для проверки типов.
1%
Используется для создания массивов.
Избежание deadlock'ов (взаимных блокировок) в многопоточном программировании — важная задача, требующая внимательного проектирования и разработки. Deadlock происходит, когда два или более потока не могут продолжать выполнение, потому что каждый из них ожидает освобождения ресурса, удерживаемого другим потоком. Вот несколько стратегий и методов для предотвращения deadlock'ов:
object lock1 = new object();
object lock2 = new object();
public void Method1()
{
lock (lock1)
{
lock (lock2)
{
// Действия с lock1 и lock2
}
}
}
public void Method2()
{
lock (lock1)
{
lock (lock2)
{
// Действия с lock1 и lock2
}
}
}
Monitor.TryEnter или Mutex.WaitOne, чтобы предотвратить бесконечное ожидание ресурсов.object lockObject = new object();
public void MethodWithTimeout()
{
bool lockTaken = false;
try
{
Monitor.TryEnter(lockObject, TimeSpan.FromSeconds(1), ref lockTaken);
if (lockTaken)
{
// Работа с lockObject
}
else
{
// Обработка ситуации, когда блокировка не была взята
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(lockObject);
}
}
}
lock, Monitor, Mutex), используйте примитивы, которые уменьшают вероятность deadlock'ов, такие как SemaphoreSlim или ReaderWriterLockSlim.SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
public async Task MethodWithSemaphore()
{
await semaphore.WaitAsync();
try
{
// Действия, требующие синхронизации
}
finally
{
semaphore.Release();
}
}
object lockObject = new object();
public void Method()
{
// Выполняйте сложные операции вне блока lock
var data = GetData();
lock (lockObject)
{
// Выполняйте только необходимые действия внутри блока lock
ProcessData(data);
}
}
public object GetData()
{
// Долговременная операция
}
public void ProcessData(object data)
{
// Короткая операция
}
async и await, может помочь уменьшить блокировки потоков.public async Task MethodAsync()
{
await Task.Run(() =>
{
// Выполнение асинхронной работы
});
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2