Полиморфизм в объектно-ориентированном программировании (ООП) — это способность объектов разного типа обрабатывать данные через единый интерфейс. В C# существует несколько видов полиморфизма, которые можно разделить на две основные категории: компиляторный (статический) полиморфизм и временный (динамический) полиморфизм. Рассмотрим каждый из них более подробно.
Этот тип полиморфизма определяется на этапе компиляции. К нему относятся:
class MathOperations
{
public int Add(int a, int b)
{
return a + b;
}
public double Add(double a, double b)
{
return a + b;
}
}
class Complex
{
public double Real { get; set; }
public double Imaginary { get; set; }
public static Complex operator +(Complex c1, Complex c2)
{
return new Complex { Real = c1.Real + c2.Real, Imaginary = c1.Imaginary + c2.Imaginary };
}
}
Этот тип полиморфизма определяется на этапе выполнения программы. К нему относятся:
virtual в базовом классе и override в производном классе.class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("Animal sound");
}
}
class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Bark");
}
}
interface IShape
{
void Draw();
}
class Circle : IShape
{
public void Draw()
{
Console.WriteLine("Drawing Circle");
}
}
class Square : IShape
{
public void Draw()
{
Console.WriteLine("Drawing Square");
}
}
class Printer
{
public void Print(string message)
{
Console.WriteLine(message);
}
public void Print(int number)
{
Console.WriteLine(number);
}
}
class Program
{
static void Main()
{
Printer printer = new Printer();
printer.Print("Hello, world!");
printer.Print(123);
}
}
class Program
{
static void Main()
{
Animal myDog = new Dog();
myDog.MakeSound(); // Output: Bark
}
}
class Program
{
static void Main()
{
IShape circle = new Circle();
IShape square = new Square();
circle.Draw(); // Output: Drawing Circle
square.Draw(); // Output: Drawing Square
}
}
Полиморфизм в C# бывает двух видов: статический и динамический. Статический включает перегрузку методов и операторов, а динамический включает переопределение методов и использование интерфейсов. Полиморфизм позволяет использовать единый интерфейс для работы с объектами разных типов.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍3🤔1
Принципы SOLID — это пять основных принципов объектно-ориентированного проектирования и программирования, которые помогают создавать гибкие и поддерживаемые системы:
Пример:
public class Report
{
public string Text { get; set; }
public void PrintReport()
{
// Логика печати отчета
}
}
public class ReportSaver
{
public void SaveToFile(Report report, string filePath)
{
// Логика сохранения отчета в файл
}
}
Пример:
public abstract class Shape
{
public abstract double Area();
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double Area()
{
return Math.PI * Radius * Radius;
}
}
public class Square : Shape
{
public double Side { get; set; }
public override double Area()
{
return Side * Side;
}
}
Пример:
public class Bird
{
public virtual void Fly()
{
// Логика полета
}
}
public class Sparrow : Bird
{
public override void Fly()
{
// Логика полета воробья
}
}
public class Ostrich : Bird
{
public override void Fly()
{
throw new NotImplementedException();
}
}
Здесь принцип нарушен, так как страус не может летать. Лучше не наследовать страуса от класса Bird, если метод Fly не применим ко всем подклассам.
Пример:
public interface IPrinter
{
void Print();
}
public interface IScanner
{
void Scan();
}
public class MultiFunctionPrinter : IPrinter, IScanner
{
public void Print()
{
// Логика печати
}
public void Scan()
{
// Логика сканирования
}
}
public class SimplePrinter : IPrinter
{
public void Print()
{
// Логика печати
}
}
Пример:
public interface IMessageSender
{
void SendMessage(string message);
}
public class EmailSender : IMessageSender
{
public void SendMessage(string message)
{
// Логика отправки email
}
}
public class Notification
{
private readonly IMessageSender _messageSender;
public Notification(IMessageSender messageSender)
{
_messageSender = messageSender;
}
public void Send(string message)
{
_messageSender.SendMessage(message);
}
}
Принципы SOLID помогают создавать гибкие и поддерживаемые системы. Это принципы единственной ответственности, открытости/закрытости, подстановки Лисков, разделения интерфейса и инверсии зависимостей. Они направлены на улучшение структуры и качества кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤯1
Микросервисная архитектура предлагает множество преимуществ, таких как независимая разработка и развёртывание компонентов, повышенная масштабируемость и устойчивость к сбоям. Однако, несмотря на все эти плюсы, существуют и некоторые недостатки, которые необходимо учитывать при принятии решения о переходе на микросервисную архитектуру.
Описание:
Проблемы:
Описание:
Проблемы:
Описание:
Проблемы:
Описание:
Проблемы:
Описание:
Проблемы:
Описание:
Проблемы:
Предположим, у нас есть система микросервисов для интернет-магазина. Один микросервис отвечает за управление товарами, другой за обработку заказов, а третий за платежи. В монолитной архитектуре все компоненты находятся в одном приложении, и взаимодействие между ними происходит напрямую через вызовы методов. В микросервисной архитектуре взаимодействие будет происходить через сетевые запросы.
Микросервисная архитектура может усложнить управление системой, увеличить сетевые задержки, усложнить тестирование и поддержание консистентности данных, повысить требования к инфраструктуре и создать организационные сложности.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍3
Anonymous Quiz
14%
private
74%
protected
10%
internal
1%
public
👍1
.NET Core — это кроссплатформенная, высокопроизводительная и модульная среда выполнения, разработанная компанией Microsoft. Она предназначена для создания современных приложений, которые могут быть развёрнуты на различных операционных системах, включая Windows, macOS и Linux. .NET Core является частью более широкой экосистемы .NET и представляет собой значительное развитие по сравнению с традиционным .NET Framework. Рассмотрим основные особенности и компоненты .NET Core подробнее.
Для создания простого консольного приложения на .NET Core можно использовать следующие команды CLI:
dotnet new console -n MyConsoleApp
cd MyConsoleApp
Program.cs и внесите изменения: using System;
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, .NET Core!");
}
}
}
dotnet run
.NET Core — это кроссплатформенная, высокопроизводительная и модульная среда выполнения, созданная Microsoft. Она поддерживает Windows, macOS и Linux, позволяет создавать современные приложения и является частью экосистемы .NET.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Anonymous Quiz
1%
Public
9%
Protected
85%
Private
5%
Internal
👀5
В программировании куча (heap) — это область памяти, которая используется для динамического распределения памяти. В отличие от стека, где память выделяется и освобождается автоматически при вызове и завершении функций, куча позволяет разработчику вручную контролировать выделение и освобождение памяти. В контексте C# и .NET, куча имеет свои особенности, связанные с управлением памятью и сборкой мусора (Garbage Collection).
new.Когда вы создаете новый объект в C#, он размещается в управляемой куче. Рассмотрим простой пример:
class Program
{
static void Main()
{
Person person = new Person();
person.Name = "John";
Console.WriteLine(person.Name);
}
}
class Person
{
public string Name { get; set; }
}
В этом примере:
Person person = new Person(); — создается новый объект типа Person, и память для этого объекта выделяется в куче.Person, когда он больше не нужен (например, после завершения метода Main).int, float, структуры) и указателей на объекты.Преимущества:
Недостатки:
Куча — это область памяти, используемая для динамического распределения памяти объектов в процессе выполнения программы. В C# управление памятью в куче осуществляется автоматически с помощью сборщика мусора. Куча предоставляет гибкость, но может быть менее эффективной по сравнению со стеком.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Anonymous Quiz
6%
Наследование
72%
Полиморфизм
4%
Инкапсуляция
19%
Абстракция
Интерфейсы в C# используются для определения контрактов, которые классы должны реализовать, и играют важную роль в создании гибких и масштабируемых приложений. Вот основные случаи их использования:
public interface ILogger
{
void Log(string message);
}
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
public interface IShape
{
double Area();
}
public class Circle : IShape
{
public double Radius { get; set; }
public double Area() => Math.PI * Radius * Radius;
}
public class Square : IShape
{
public double Side { get; set; }
public double Area() => Side * Side;
}
public interface IDataAccess
{
void SaveData(string data);
}
public class DatabaseAccess : IDataAccess
{
public void SaveData(string data)
{
// Сохранение данных в базу данных
}
}
public class FileAccess : IDataAccess
{
public void SaveData(string data)
{
// Сохранение данных в файл
}
}
public class DataService
{
private readonly IDataAccess _dataAccess;
public DataService(IDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public void Save(string data)
{
_dataAccess.SaveData(data);
}
}
public interface IFlyable
{
void Fly();
}
public interface IWalkable
{
void Walk();
}
public class Bird : IFlyable, IWalkable
{
public void Fly()
{
// Логика полета
}
public void Walk()
{
// Логика ходьбы
}
}
public interface IEmailService
{
void SendEmail(string to, string subject, string body);
}
public class EmailService : IEmailService
{
public void SendEmail(string to, string subject, string body)
{
// Логика отправки email
}
}
public class Notification
{
private readonly IEmailService _emailService;
public Notification(IEmailService emailService)
{
_emailService = emailService;
}
public void NotifyUser(string userEmail)
{
_emailService.SendEmail(userEmail, "Notification", "You have a new notification.");
}
}
Интерфейсы используются для определения контрактов, поддержки полиморфизма, ослабления связей между компонентами, реализации множественного наследования, инъекции зависимостей и упрощения тестирования. Они помогают создать гибкую и поддерживаемую архитектуру приложений.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2🤯1
Anonymous Quiz
21%
Union
49%
Intersect
8%
Concat
22%
Join
👀5
Мультикаст-делегат в C# - это тип делегата, который может ссылаться на несколько методов. Это позволяет вызывать несколько методов в одном вызове делегата. Такая возможность полезна для выполнения последовательности действий, таких как уведомление нескольких подписчиков о событии.
Создадим простой пример, где мультикаст-делегат используется для уведомления нескольких методов:
using System;
public class Program
{
// Определяем делегат, который принимает строку и ничего не возвращает
public delegate void Notify(string message);
// Метод, который соответствует сигнатуре делегата
public static void SendEmail(string message)
{
Console.WriteLine($"Email sent: {message}");
}
// Другой метод, который соответствует сигнатуре делегата
public static void LogMessage(string message)
{
Console.WriteLine($"Log entry: {message}");
}
public static void Main()
{
// Создаем экземпляр делегата и добавляем методы
Notify notifyDel = SendEmail;
notifyDel += LogMessage;
// Вызываем делегат
notifyDel("System update available.");
// Удаляем метод из делегата
notifyDel -= LogMessage;
// Вызываем делегат снова
notifyDel("Security patch applied.");
}
}
Notify, который принимает строку в качестве параметра и не возвращает значение.SendEmail и LogMessage, которые соответствуют сигнатуре делегата Notify.LogMessage из списка вызовов делегата.Мультикаст-делегат - это делегат, который может ссылаться на несколько методов и вызывать их последовательно. Это полезно для выполнения нескольких действий в одном вызове, таких как уведомление нескольких подписчиков о событии.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
Anonymous Quiz
86%
finally
12%
catch
0%
dispose
1%
using
IoC (Inversion of Control) контейнеры – это фреймворки или библиотеки, которые управляют созданием и внедрением зависимостей в приложении. Они помогают реализовать принцип внедрения зависимостей (Dependency Injection), что делает код более гибким, тестируемым и легко расширяемым.
Рассмотрим простой пример использования популярного IoC-контейнера Autofac в C#:
public interface ILogger
{
void Log(string message);
}
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
public interface IService
{
void Serve();
}
public class Service : IService
{
private readonly ILogger _logger;
public Service(ILogger logger)
{
_logger = logger;
}
public void Serve()
{
_logger.Log("Service Called");
}
}
using Autofac;
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
// Регистрируем зависимости
builder.RegisterType<ConsoleLogger>().As<ILogger>();
builder.RegisterType<Service>().As<IService>();
// Строим контейнер
var container = builder.Build();
// Разрешаем зависимости
var service = container.Resolve<IService>();
service.Serve();
}
}
ILogger и IService, а также их реализации ConsoleLogger и Service.ContainerBuilder регистрируем классы ConsoleLogger и Service как реализации соответствующих интерфейсов.Serve у объекта Service, который использует ConsoleLogger для логирования.IoC-контейнеры управляют созданием и внедрением зависимостей в приложении, упрощая тестирование и организацию кода. Они позволяют регистрировать и разрешать зависимости, делая код более гибким и легко расширяемым.
Please open Telegram to view this post
VIEW IN TELEGRAM
Anonymous Quiz
64%
Dispose()
12%
SuppressFinalize()
22%
Collect()
2%
Abort()
👾1
Принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP) - это один из пяти принципов SOLID, который гласит, что объекты подтипов должны быть заменяемы объектами базового типа без нарушения правильности работы программы. Это означает, что если класс
B является подтипом класса A, то объекты класса A могут быть заменены объектами класса B без изменения желаемого поведения программы.Рассмотрим пример, где нарушение LSP приводит к некорректному поведению программы:
public class Rectangle
{
public virtual int Width { get; set; }
public virtual int Height { get; set; }
public int GetArea()
{
return Width * Height;
}
}
public class Square : Rectangle
{
public override int Width
{
set { base.Width = base.Height = value; }
}
public override int Height
{
set { base.Width = base.Height = value; }
}
}
В этом примере
Square (квадрат) наследует от Rectangle (прямоугольник). Однако, квадрат имеет особое свойство: его ширина и высота всегда равны. При попытке установить ширину или высоту квадрата, изменяется и другое значение, что нарушает поведение прямоугольника.Лучше использовать композицию вместо наследования для избежания такой проблемы:
public interface IShape
{
int GetArea();
}
public class Rectangle : IShape
{
public int Width { get; set; }
public int Height { get; set; }
public int GetArea()
{
return Width * Height;
}
}
public class Square : IShape
{
public int SideLength { get; set; }
public int GetArea()
{
return SideLength * SideLength;
}
}
Rectangle и Square реализуют интерфейс IShape, но теперь они не наследуются друг от друга и имеют свои собственные свойства и методы.Принцип подстановки Лисков гласит, что объекты подтипов должны быть заменяемы объектами базового типа без нарушения работы программы. Это необходимо для повышения предсказуемости, надежности и расширяемости кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5👾1
Anonymous Quiz
73%
virtual
14%
abstract
12%
override
1%
sealed
В C# существует множество коллекций, которые предоставляются в стандартной библиотеке .NET. Они делятся на несколько категорий, каждая из которых предназначена для различных сценариев использования. Вот основные типы коллекций:
List<int> numbers = new List<int> { 1, 2, 3, 4 };
numbers.Add(5);
Dictionary<string, int> ages = new Dictionary<string, int>
{
{ "Alice", 30 },
{ "Bob", 25 }
};
int aliceAge = ages["Alice"];
HashSet<string> fruits = new HashSet<string> { "Apple", "Banana" };
fruits.Add("Apple"); // Не добавит дубликат
Queue<string> queue = new Queue<string>();
queue.Enqueue("first");
queue.Enqueue("second");
string item = queue.Dequeue(); // "first"
Stack<string> stack = new Stack<string>();
stack.Push("first");
stack.Push("second");
string item = stack.Pop(); // "second"
LinkedList<int> linkedList = new LinkedList<int>();
linkedList.AddLast(1);
linkedList.AddLast(2);
SortedList<string, int> sortedList = new SortedList<string, int>
{
{ "Alice", 30 },
{ "Bob", 25 }
};
SortedList, но использует бинарное дерево для хранения элементов. SortedDictionary<string, int> sortedDict = new SortedDictionary<string, int>
{
{ "Alice", 30 },
{ "Bob", 25 }
};
SortedSet<int> sortedSet = new SortedSet<int> { 3, 1, 2 };
Dictionary, предназначенная для безопасного использования в многопоточных приложениях. ConcurrentDictionary<string, int> concurrentDict = new ConcurrentDictionary<string, int>();
concurrentDict.TryAdd("Alice", 30);
Queue. ConcurrentQueue<string> concurrentQueue = new ConcurrentQueue<string>();
concurrentQueue.Enqueue("first");
Stack. ConcurrentStack<string> concurrentStack = new ConcurrentStack<string>();
concurrentStack.Push("first");
BlockingCollection<int> blockingCollection = new BlockingCollection<int>(5);
blockingCollection.Add(1);
В C# есть множество коллекций для различных целей, включая
List, Dictionary, HashSet, Queue, Stack, специализированные коллекции, такие как LinkedList, SortedList, а также коллекции для параллельного программирования, такие как ConcurrentDictionary и BlockingCollection.Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Dependency Injection (DI), или инъекция зависимости, — это шаблон проектирования, который позволяет объектам получить свои зависимости от внешних источников, а не создавать их самостоятельно. Этот подход улучшает тестируемость, расширяемость и поддерживаемость кода, делая его более гибким и модульным.
A использует класс B для выполнения своих задач, то B является зависимостью для A.public class Service
{
private readonly IRepository _repository;
public Service(IRepository repository)
{
_repository = repository;
}
public void DoWork()
{
_repository.Save();
}
}
public class Service
{
public IRepository Repository { get; set; }
public void DoWork()
{
Repository.Save();
}
}
public class Service
{
private IRepository _repository;
public void SetRepository(IRepository repository)
{
_repository = repository;
}
public void DoWork()
{
_repository.Save();
}
}
IoC-контейнеры (контейнеры инверсии управления) управляют созданием и жизненным циклом зависимостей, а также автоматизируют процесс их инъекции. Пример использования популярного IoC-контейнера Autofac:
using Autofac;
var builder = new ContainerBuilder();
builder.RegisterType<Repository>().As<IRepository>();
builder.RegisterType<Service>().As<IService>();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<IService>();
service.DoWork();
}
Dependency Injection (DI) — это метод предоставления зависимостей объекту извне, что делает код более гибким, тестируемым и поддерживаемым. DI может осуществляться через конструкторы, свойства или методы, а IoC-контейнеры автоматизируют процесс управления зависимостями.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Anonymous Quiz
18%
private
9%
protected
61%
internal
13%
protected internal
В C# списки (List) и массивы (Array) являются двумя основными типами коллекций, но они имеют различия в своих свойствах, возможностях и сценариях использования. Рассмотрим основные различия между ними.
int[] numbers = new int[5]; // Массив из 5 элементов
string[] words = new string[] { "apple", "banana", "cherry" };
int firstNumber = numbers[0]; // Быстрый доступ по индексу
Length. int length = numbers.Length; // Длина массива
List<int> numbersList = new List<int> { 1, 2, 3, 4, 5 };
numbersList.Add(6); // Добавление элемента увеличивает размер списка
List<string> wordsList = new List<string> { "apple", "banana", "cherry" };
int firstNumberInList = numbersList[0]; // Быстрый доступ по индексу
Add, Remove, Find, Count и многие другие, что делает их более удобными для работы с динамическими данными. int count = numbersList.Count; // Количество элементов в списке
numbersList.Remove(3); // Удаление элемента
Массив:
int[] numbersArray = new int[] { 1, 2, 3, 4, 5 };
int firstElement = numbersArray[0];
numbersArray[2] = 10;
Console.WriteLine(numbersArray.Length);Список:
List<int> numbersList = new List<int> { 1, 2, 3, 4, 5 };
numbersList.Add(6);
int firstElementInList = numbersList[0];
numbersList[2] = 10;
Console.WriteLine(numbersList.Count);
numbersList.Remove(4);Массивы имеют фиксированный размер и обеспечивают быстрый доступ к элементам, но менее гибкие. Списки имеют динамический размер и предоставляют больше методов для работы с элементами, но могут быть менее эффективны по памяти.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6