День сто двадцать шестой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
13. В чем разница между поздним и ранним связыванием в C#?
Концепции раннего связывания и позднего связывания относятся к полиморфизму в C#. Полиморфизм - это особенность объектно-ориентированного программирования, позволяющая языку использовать одно и то же имя метода в разных формах.
Есть 2 способа достижения этого:
1. Во время компиляции – статический полиморфизм, раннее связывание или перегрузка (overloading).
2. Во время выполнения – динамический полиморфизм, позднее связывание или переопределение (overriding).
Полиморфизм времени компиляции или раннее связывание
При перегрузке методы имеют одно и то же имя, но разные сигнатуры. Это также известно, как полиморфизм времени компиляции, поскольку решение о том, какой метод вызывать, принимается во время компиляции. Компилятор C# проверяет количество передаваемых параметров и типы параметров и принимает решение, какой метод вызывать, либо выдаёт ошибку времени компиляции, если подходящий метод не найден:
Здесь имена и сигнатуры методов (количество параметров и типы параметров) должны быть одинаковыми, однако методы могут иметь различную реализацию. Переопределение метода может быть выполнено с использованием наследования. Компилятор решает, какой метод вызывать, во время выполнения. Если доступен переопределённый метод, будет вызван он, в противном случае будет вызван метод базового класса. В следующем примере классы
Самые часто задаваемые вопросы на собеседовании по C#
13. В чем разница между поздним и ранним связыванием в C#?
Концепции раннего связывания и позднего связывания относятся к полиморфизму в C#. Полиморфизм - это особенность объектно-ориентированного программирования, позволяющая языку использовать одно и то же имя метода в разных формах.
Есть 2 способа достижения этого:
1. Во время компиляции – статический полиморфизм, раннее связывание или перегрузка (overloading).
2. Во время выполнения – динамический полиморфизм, позднее связывание или переопределение (overriding).
Полиморфизм времени компиляции или раннее связывание
При перегрузке методы имеют одно и то же имя, но разные сигнатуры. Это также известно, как полиморфизм времени компиляции, поскольку решение о том, какой метод вызывать, принимается во время компиляции. Компилятор C# проверяет количество передаваемых параметров и типы параметров и принимает решение, какой метод вызывать, либо выдаёт ошибку времени компиляции, если подходящий метод не найден:
public class TestDataПолиморфизм времени выполнения или позднее связывание
{
public int Add(int a, int b, int c)
{
return a + b + c;
}
public int Add(int a, int b)
{
return a + b;
}
}
…
TestData data = new TestData();
int sum1 = dataClass.Add(45, 34, 67);
int sum2 = dataClass.Add(23, 34);
Здесь имена и сигнатуры методов (количество параметров и типы параметров) должны быть одинаковыми, однако методы могут иметь различную реализацию. Переопределение метода может быть выполнено с использованием наследования. Компилятор решает, какой метод вызывать, во время выполнения. Если доступен переопределённый метод, будет вызван он, в противном случае будет вызван метод базового класса. В следующем примере классы
A
и B
переопределяют метод ToString
базового класса object
. Поэтому при выводе их в консоль будут использованы переопределённые версии, а при выводе класса C
будет использован метод ToString
базового класса object
:public class AВывод:
{
public override string ToString() => "Class A";
}
public class B
{
public override string ToString() => "Class B";
}
public class C {}
…
var objects = new object[] { new A(), new B(), new C() };
foreach (var obj in objects)
{
Console.WriteLine(obj);
}
Class AИсточник: https://www.c-sharpcorner.com
Class B
ConsoleApp1.C
👍1
День сто двадцать седьмой. #TipsAndTricks
27. Точка прерывания на автоматически реализованном свойстве
Если в вашей компании по финансовым, юридическим, религиозным или каким-то иным причинам используют старую версию Visual Studio, то вам порой приходится сталкиваться с проблемами, давно решёнными в более современных версиях.
Проблема (в VS версии 2013)
C# поддерживает автоматически реализованные свойства. Во время отладки иногда полезно устанавливать точки останова при обращении к свойству, особенно когда оно вызывается из нескольких мест, и утомительно находить их все и ставить множество точек останова. Итак, рассмотрим следующий пример:
Решение для VS2013 – функциональные точки останова
Создайте новую функциональную точку останова (
В VS версии 2015 и позже это просто работает. Ставьте точку останова на строках 4 или 5, и отладчик остановится на этой строке. Чтобы перейти к вызывающему коду, просто щелкните на следующую строку в стеке вызовов.
Источник: https://devblogs.microsoft.com/devops/set-breakpoints-on-auto-implemented-properties-with-visual-studio-2015/
27. Точка прерывания на автоматически реализованном свойстве
Если в вашей компании по финансовым, юридическим, религиозным или каким-то иным причинам используют старую версию Visual Studio, то вам порой приходится сталкиваться с проблемами, давно решёнными в более современных версиях.
Проблема (в VS версии 2013)
C# поддерживает автоматически реализованные свойства. Во время отладки иногда полезно устанавливать точки останова при обращении к свойству, особенно когда оно вызывается из нескольких мест, и утомительно находить их все и ставить множество точек останова. Итак, рассмотрим следующий пример:
namespace MyName {Если вы попытаетесь установить точку останова на строках 4 или 5, то, к сожалению, точка останова переместится в ближайшее подходящее место, а не останется на этой строке.
class Program {
static bool MyProperty {
get; // строка 4
set; // строка 5
}
static void Main() {
if ((new System.Random()).Next(3) == 1)
MyProperty = true; // строка 9
else
MyProperty = false; // строка 11
System.Diagnostics.Debugger.Break(); // строка 12
}
}
}
Решение для VS2013 – функциональные точки останова
Создайте новую функциональную точку останова (
Ctrl + B
), как показано на рисунке ниже (в этом случае просто set_MyProperty
также будет работать). Теперь, когда вы нажмёте F5, отладчик остановится на строке 9 или 11, в зависимости от того, кому повезёт вызвать метод-мутатор свойства.В VS версии 2015 и позже это просто работает. Ставьте точку останова на строках 4 или 5, и отладчик остановится на этой строке. Чтобы перейти к вызывающему коду, просто щелкните на следующую строку в стеке вызовов.
Источник: https://devblogs.microsoft.com/devops/set-breakpoints-on-auto-implemented-properties-with-visual-studio-2015/
День сто двадцать восьмой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
14. В чём разница между IEnumerable и IQueryable?
При работе с базой данных иногда можно запутаться. Могут возникнуть некоторые вопросы, например, что использовать для извлечения данных из БД,
Если коротко:
-
-
Разница в том, что
В случае
По сути, есть два идентичных набора расширений LINQ.
Сигнатура для
При использовании
Зачем заморачиваться с этими деревьями выражений? Я просто хочу, чтобы Where фильтровал мои данные. Основная причина в том, что Entity Framework и Linq2SQL могут преобразовывать деревья выражений непосредственно в SQL, поэтому ваш код будет выполняться намного быстрее.
Это похоже на бесплатное повышение производительности. То есть надо везде использовать AsQueryable? Нет,
Источники:
- https://www.c-sharpcorner.com
- https://stackoverflow.com/questions/2876616/returning-ienumerablet-vs-iqueryablet
Самые часто задаваемые вопросы на собеседовании по C#
14. В чём разница между IEnumerable и IQueryable?
При работе с базой данных иногда можно запутаться. Могут возникнуть некоторые вопросы, например, что использовать для извлечения данных из БД,
IEnumerable
или IQueryable
?Если коротко:
-
IEnumerable
- выполняет запрос SELECT
на стороне сервера, загружает все данные в память на стороне клиента, а затем выполняет фильтрацию.-
IQueryable
- выполняет запрос SELECT
на стороне сервера со всеми фильтрами.Разница в том, что
IQueryable<T>
- это интерфейс, который позволяет работать LINQ-to-SQL (на самом деле, LINQ-to-чтоугодно). Поэтому, если вы дополнительно уточните свой запрос в IQueryable<T>
, этот запрос будет выполнен в базе данных, если это возможно.В случае
IEnumerable<T>
это будет LINQ-to-object, то есть все объекты, соответствующие исходному запросу, должны быть загружены в память из базы данных:IQueryable<Customer> custs = ...;Этот код выполнит SQL-запрос для выбора только золотых клиентов. А вот следующий код выполнит исходный запрос к базе данных, а затем отфильтрует не-золотых клиентов в памяти:
// Затем...
var goldCustomers = custs.Where(c => c.IsGold);
IEnumerable<Customer> custs = ...;Это довольно важное различие, и работа с
// Затем...
var goldCustomers = custs.Where(c => c.IsGold);
IQueryable
может во многих случаях избавить вас от возвращения слишком большого количества строк из базы данных. Другим ярким примером является разбиение на страницы: если вы используете Take
и Skip
с IQueryable
, вы получите только запрошенные строки, а выполнение этого в IEnumerable
приведет к загрузке в память всех строк.По сути, есть два идентичных набора расширений LINQ.
Where
, Sum
, Count
, FirstOrDefault
и т.д. имеют две версии: одна, которая принимает функции, и другая, которая принимает выражения.Сигнатура для
IEnumerable
: Where(Func<Customer, bool> predicate)
Сигнатура для IQueryable
: Where(Expression<Func<Customer, bool>> predicate)
Вы, вероятно, использовали обе версии, не осознавая этого, потому что обе вызываются с использованием идентичного синтаксиса Where(x => x.City == "<City>")
, который работает как для IEnumerable
, так и для IQueryable
.При использовании
Where
с IEnumerable
компилятор передает в Where
скомпилированную функцию. А при использовании Where
с IQueryable
компилятор передает в Where
дерево выражений. Дерево выражений похоже на отражение, но для кода. Компилятор преобразует ваш код в структуру данных, которая описывает, что ваш код делает в формате, который легко усваивается.Зачем заморачиваться с этими деревьями выражений? Я просто хочу, чтобы Where фильтровал мои данные. Основная причина в том, что Entity Framework и Linq2SQL могут преобразовывать деревья выражений непосредственно в SQL, поэтому ваш код будет выполняться намного быстрее.
Это похоже на бесплатное повышение производительности. То есть надо везде использовать AsQueryable? Нет,
IQueryable
полезен, только если базовый поставщик данных может что-то с ним сделать. Преобразование обычного List
в IQueryable
не даст вам никакой выгоды.Источники:
- https://www.c-sharpcorner.com
- https://stackoverflow.com/questions/2876616/returning-ienumerablet-vs-iqueryablet
👍1
День сто двадцать девятый. #Шаблоны
Шаблоны проектирования в C#
Типы шаблонов проектирования:
- Порождающие
- Структурные
- Поведенческие
Порождающие шаблоны
Шаблоны, имеющие дело с процессом создания объектов:
1. Абстрактная фабрика - создание экземпляров нескольких классов, принадлежащих к разным семействам.
2. Строитель - отделяет создание объекта от его представления.
3. Фабричный метод - предоставляет подклассам интерфейс для создания экземпляров некоторого класса.
4. Прототип - указывает тип объектов, создаваемых с использованием прототипа, и создаёт новые объекты, скопировав этот прототип.
5. Одиночка - гарантирует, что класс может иметь только один экземпляр.
Структурные шаблоны
Эти шаблоны имеют дело с композицией структур объектов:
1. Адаптер - интерфейсы классов варьируются в зависимости от требований.
2. Мост - абстракция уровня класса отделена от его реализации.
3. Составной - при этом подходе отдельные объекты и группа объектов обрабатываются одинаково.
4. Декоратор - функциональность назначается объекту.
5. Фасад - для группы интерфейсов, имеющих общее сходство, создается общий интерфейс.
6. Легковесный - концепция совместного использования группы объектов небольшого размера.
7. Прокси - объект сложный и нуждается в совместном использовании, создаются его копии. Эти копии называются объектами прокси.
Поведенческие шаблоны
Эти шаблоны касаются процесса общения, управления отношениями и ответственности между объектами:
1. Цепочка ответственности - в этом шаблоне объекты взаимодействуют друг с другом в зависимости от логических решений, принятых классом.
2. Команда - в этом шаблоне объекты инкапсулируют методы и передаваемые им параметры.
3. Наблюдатель - определяет зависимость «один ко многим» между объектами, чтобы при изменении состояния одного объекта все его наблюдатели уведомлялись и обновлялись автоматически.
4. Интерпретатор - способ включения языковых элементов в программу.
5. Итератор - предоставляет способ последовательного доступа к элементам перечислимого объекта без раскрытия подробностей реализации.
6. Посредник - определяет объект, который инкапсулирует то, как взаимодействует набор объектов. Другими словами, он определяет упрощенную связь между классами.
7. Хранитель - не нарушая инкапсуляцию, захватывает и запоминает внутреннее состояние объекта, так что объект может быть восстановлен в этом состоянии позже.
8. Состояние - позволяет объекту изменять свое поведение при изменении его внутреннего состояния. Объект появляется, чтобы изменить свой класс.
9. Стратегия - определяет семейство алгоритмов, инкапсулирует каждый и делает их взаимозаменяемыми. Стратегия позволяет алгоритму варьироваться независимо от клиентов, которые его используют.
10. Посетитель - определяет новую операцию для класса без изменений.
11. Шаблонный метод – позволяет отложить реализацию алгоритма до подклассов.
Источник: https://www.c-sharpcorner.com
Шаблоны проектирования в C#
Типы шаблонов проектирования:
- Порождающие
- Структурные
- Поведенческие
Порождающие шаблоны
Шаблоны, имеющие дело с процессом создания объектов:
1. Абстрактная фабрика - создание экземпляров нескольких классов, принадлежащих к разным семействам.
2. Строитель - отделяет создание объекта от его представления.
3. Фабричный метод - предоставляет подклассам интерфейс для создания экземпляров некоторого класса.
4. Прототип - указывает тип объектов, создаваемых с использованием прототипа, и создаёт новые объекты, скопировав этот прототип.
5. Одиночка - гарантирует, что класс может иметь только один экземпляр.
Структурные шаблоны
Эти шаблоны имеют дело с композицией структур объектов:
1. Адаптер - интерфейсы классов варьируются в зависимости от требований.
2. Мост - абстракция уровня класса отделена от его реализации.
3. Составной - при этом подходе отдельные объекты и группа объектов обрабатываются одинаково.
4. Декоратор - функциональность назначается объекту.
5. Фасад - для группы интерфейсов, имеющих общее сходство, создается общий интерфейс.
6. Легковесный - концепция совместного использования группы объектов небольшого размера.
7. Прокси - объект сложный и нуждается в совместном использовании, создаются его копии. Эти копии называются объектами прокси.
Поведенческие шаблоны
Эти шаблоны касаются процесса общения, управления отношениями и ответственности между объектами:
1. Цепочка ответственности - в этом шаблоне объекты взаимодействуют друг с другом в зависимости от логических решений, принятых классом.
2. Команда - в этом шаблоне объекты инкапсулируют методы и передаваемые им параметры.
3. Наблюдатель - определяет зависимость «один ко многим» между объектами, чтобы при изменении состояния одного объекта все его наблюдатели уведомлялись и обновлялись автоматически.
4. Интерпретатор - способ включения языковых элементов в программу.
5. Итератор - предоставляет способ последовательного доступа к элементам перечислимого объекта без раскрытия подробностей реализации.
6. Посредник - определяет объект, который инкапсулирует то, как взаимодействует набор объектов. Другими словами, он определяет упрощенную связь между классами.
7. Хранитель - не нарушая инкапсуляцию, захватывает и запоминает внутреннее состояние объекта, так что объект может быть восстановлен в этом состоянии позже.
8. Состояние - позволяет объекту изменять свое поведение при изменении его внутреннего состояния. Объект появляется, чтобы изменить свой класс.
9. Стратегия - определяет семейство алгоритмов, инкапсулирует каждый и делает их взаимозаменяемыми. Стратегия позволяет алгоритму варьироваться независимо от клиентов, которые его используют.
10. Посетитель - определяет новую операцию для класса без изменений.
11. Шаблонный метод – позволяет отложить реализацию алгоритма до подклассов.
Источник: https://www.c-sharpcorner.com
День сто тридцать первый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
15. В чем разница между Array.CopyTo() и Array.Clone()?
Метод
Однако есть различия и рекомендации по использованию этих методов.
System.Array.Clone:
1. Медленнее, чем
2. Требуется приведение результата к соответствующему типу;
3. Полученный массив имеет ту же длину, что и исходный.
System.Array.CopyTo:
1. Быстрее, чем Clone при копировании в массив того же типа;
2. Вызывает
- может вставлять элементы типа значения в элементы ссылочного типа, например, копируя массив
- может распаковывать элементы ссылочного типа в элементы значимого типа, например, копируя массив
- может выполнять расширенные преобразования для типов значений, например, копируя
- может выполнять даункаст элементов, например, копируя массив
- позволяет скопировать источник в целевой массив, длина которого больше, чем у источника.
Также обратите внимание, что эти методы доступны для реализации
Источник: - https://stackoverflow.com/questions/198496/difference-between-the-system-array-copyto-and-system-array-clone
Самые часто задаваемые вопросы на собеседовании по C#
15. В чем разница между Array.CopyTo() и Array.Clone()?
Метод
Clone()
возвращает новый объект массива (неглубокая копия), содержащий все элементы в исходном массиве. Метод CopyTo()
копирует элементы в другой существующий массив. Оба выполняют неглубокое копирование, то есть каждый элемент массива будет содержать ссылки на те же объекты, что и элементы в исходном массиве. Глубокая копия (которую не выполняет ни один из этих методов) создаёт новый экземпляр объекта каждого элемента, в результате чего получится другой, но идентичный объект.Однако есть различия и рекомендации по использованию этих методов.
System.Array.Clone:
1. Медленнее, чем
CopyTo
, вероятно, потому что использует Object.iss.onemberwiseClone
;2. Требуется приведение результата к соответствующему типу;
3. Полученный массив имеет ту же длину, что и исходный.
System.Array.CopyTo:
1. Быстрее, чем Clone при копировании в массив того же типа;
2. Вызывает
Array.Copy
, наследуя некоторые его полезные возможности:- может вставлять элементы типа значения в элементы ссылочного типа, например, копируя массив
int[]
в object[]
;- может распаковывать элементы ссылочного типа в элементы значимого типа, например, копируя массив
object[]
из упакованных элементов int
в массив int[]
;- может выполнять расширенные преобразования для типов значений, например, копируя
int[]
в long[]
;- может выполнять даункаст элементов, например, копируя массив
Stream[]
в MemoryStream[]
(если какой-либо элемент в исходном массиве не конвертируется в MemoryStream
, генерируется исключение);- позволяет скопировать источник в целевой массив, длина которого больше, чем у источника.
Также обратите внимание, что эти методы доступны для реализации
ICloneable
и ICollection
. Поэтому, если вы имеете дело с массивами, вам не следует использовать Clone
или CopyTo
, а вместо этого использовать Array.Copy
или Array.ConstrainedCopy
. Ограниченная копия гарантирует, что если операция копирования завершится неудачей, то состояние целевого массива не будет повреждено.Источник: - https://stackoverflow.com/questions/198496/difference-between-the-system-array-copyto-and-system-array-clone
День сто тридцать второй. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
16. Что такое модификаторы доступа в C#?
Модификаторы доступа в C# используются для определения области доступности класса или его членов. Например, открытый класс доступен всем без каких-либо ограничений, тогда как внутренний класс может быть доступен только внутри сборки.
Модификаторы доступа являются неотъемлемой частью объектно-ориентированного программирования, используются для реализации инкапсуляции и позволяют вам определить, кто имеет, а кто не имеет доступа к определенным функциям.
Модификаторы доступа в С#:
1.
2.
3.
4.
5.
6.
Особенности:
- Классы, структуры, интерфейсы и делегаты могут быть public или internal (по умолчанию).
- Члены класса, включая вложенные классы и структуры, могут иметь все возможные модификаторы доступа (по умолчанию private). Обычно доступность члена не превышает доступность типа, который его содержит. Однако открытый член внутреннего класса может быть доступен извне сборки, если он реализует методы интерфейса или переопределяет виртуальные методы, определенные в общедоступном базовом классе.
- Члены структуры, включая вложенные классы и структуры, могут быть объявлены как public, internal или private. Члены структуры не могут быть protected, потому что структуры не поддерживают наследование.
- Члены интерфейсов и перечислений всегда public. Модификаторы доступа к ним не применяются.
- Тип любого поля, свойства или события должен быть, как минимум, таким же доступным, как и сам член. Аналогично, тип возвращаемого значения и типы параметров любого метода, индексатора или делегата, должны быть, как минимум, такими же доступными, как и сам член. Т.е вы не можете иметь public метод M, который возвращает класс C, если C не public. Или вы не можете иметь protected свойство типа A, если тип A private.
- Производные классы не могут иметь большей доступности, чем их базовые типы. Т.е. не может быть public класса B, производного от internal класса A.
- Финализаторы не могут иметь модификаторов доступа.
- Пользовательские операторы всегда должны быть объявлены как public.
Замечание: Вы можете разрешить другим сборкам доступ к вашим внутренним типам с помощью атрибута
Источники:
- https://www.c-sharpcorner.com
- https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers
Самые часто задаваемые вопросы на собеседовании по C#
16. Что такое модификаторы доступа в C#?
Модификаторы доступа в C# используются для определения области доступности класса или его членов. Например, открытый класс доступен всем без каких-либо ограничений, тогда как внутренний класс может быть доступен только внутри сборки.
Модификаторы доступа являются неотъемлемой частью объектно-ориентированного программирования, используются для реализации инкапсуляции и позволяют вам определить, кто имеет, а кто не имеет доступа к определенным функциям.
Модификаторы доступа в С#:
1.
public
- доступ к типу или члену может быть получен из любого другого кода в той же сборке или другой сборке, которая на него ссылается.2.
private
- тип или член могут быть доступны только из кода в том же классе или структуре.3.
protected
- доступ к типу или члену возможен только из кода в том же классе или в классе, производном от него.4.
internal
- доступ к типу или члену возможен из любого кода в той же сборке, но не из другой сборки.5.
protected internal
– доступ к типу или члену возможен из любого кода в сборке, в которой он объявлен, или из производного от этого класса в другой сборке.6.
private protected
(с C#7.2) - доступ к типу или члену возможен только в пределах его сборки, и из кода в том же классе или в классе, производном от него.Особенности:
- Классы, структуры, интерфейсы и делегаты могут быть public или internal (по умолчанию).
- Члены класса, включая вложенные классы и структуры, могут иметь все возможные модификаторы доступа (по умолчанию private). Обычно доступность члена не превышает доступность типа, который его содержит. Однако открытый член внутреннего класса может быть доступен извне сборки, если он реализует методы интерфейса или переопределяет виртуальные методы, определенные в общедоступном базовом классе.
- Члены структуры, включая вложенные классы и структуры, могут быть объявлены как public, internal или private. Члены структуры не могут быть protected, потому что структуры не поддерживают наследование.
- Члены интерфейсов и перечислений всегда public. Модификаторы доступа к ним не применяются.
- Тип любого поля, свойства или события должен быть, как минимум, таким же доступным, как и сам член. Аналогично, тип возвращаемого значения и типы параметров любого метода, индексатора или делегата, должны быть, как минимум, такими же доступными, как и сам член. Т.е вы не можете иметь public метод M, который возвращает класс C, если C не public. Или вы не можете иметь protected свойство типа A, если тип A private.
- Производные классы не могут иметь большей доступности, чем их базовые типы. Т.е. не может быть public класса B, производного от internal класса A.
- Финализаторы не могут иметь модификаторов доступа.
- Пользовательские операторы всегда должны быть объявлены как public.
Замечание: Вы можете разрешить другим сборкам доступ к вашим внутренним типам с помощью атрибута
InternalsVisibleToAttribute
.Источники:
- https://www.c-sharpcorner.com
- https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers
День сто тридцать третий. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
17. Что такое виртуальный метод в C#?
Виртуальный метод - это метод, который можно переопределить в производных классах. Виртуальный метод имеет реализацию в базовом классе. Он используется, когда базовая функциональность метода одинакова, но иногда требуется больше функциональности в производном классе. В базовом классе создается виртуальный метод, используя ключевое слово
- Производному классу необязательно переопределять этот метод.
- Когда вызывается виртуальный метод, тип объекта во время выполнения проверяется для переопределяющего члена. Вызывается переопределяющий член в наиболее производном классе. То есть может быть вызван и исходный член, если ни один производный класс не переопределил его.
- По умолчанию методы не виртуальные. Нельзя переопределить не виртуальный метод.
- Нельзя использовать виртуальный модификатор с модификаторами
Источники: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по C#
17. Что такое виртуальный метод в C#?
Виртуальный метод - это метод, который можно переопределить в производных классах. Виртуальный метод имеет реализацию в базовом классе. Он используется, когда базовая функциональность метода одинакова, но иногда требуется больше функциональности в производном классе. В базовом классе создается виртуальный метод, используя ключевое слово
virtual
, который можно переопределить в производном классе с помощью ключевого слова override
. - Производному классу необязательно переопределять этот метод.
- Когда вызывается виртуальный метод, тип объекта во время выполнения проверяется для переопределяющего члена. Вызывается переопределяющий член в наиболее производном классе. То есть может быть вызван и исходный член, если ни один производный класс не переопределил его.
- По умолчанию методы не виртуальные. Нельзя переопределить не виртуальный метод.
- Нельзя использовать виртуальный модификатор с модификаторами
static
, abstract
, private
или override
.Источники: https://www.c-sharpcorner.com
День сто тридцать четвёртый. #ЗаметкиНаПолях
Анонимные методы
Создание анонимных методов – это способ передать блок кода в качестве параметра делегата:
- Область действия параметров анонимного метода - блок анонимного метода.
- Нельзя использовать операторы перехода (
- Анонимный метод не может получить доступ к параметрам
- В пределах блока анонимного метода нельзя получить доступ к небезопасному коду.
- Анонимные методы не допускаются в левой части оператора
- Локальные переменные и параметры, определённые в той же области, что и анонимный метод, называются внешними переменными анонимного метода:
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/anonymous-methods
Анонимные методы
Создание анонимных методов – это способ передать блок кода в качестве параметра делегата:
button1.Click += delegate(System.Object o, EventArgs e)…
{ MessageBox.Show("Click!"); };
// Создание делегатаАнонимные методы упрощают создание экземпляров делегатов, т.к. не нужно создавать отдельный именованный метод. Это может быть полезно в ситуации, когда создание метода не требуется, например, при создании нового потока:
delegate void Del(int x);
// Инициализация делегата анонимным методом
Del d = delegate(int k) { /* … */ };
void StartThread()Замечания
{
Thread t1 = new Thread
(delegate()
{
Console.Write("Hello, ");
Console.WriteLine("World!");
});
t1.Start();
}
- Область действия параметров анонимного метода - блок анонимного метода.
- Нельзя использовать операторы перехода (
goto
, break
или continue
) из анонимного метода во внешний код, либо наоборот.- Анонимный метод не может получить доступ к параметрам
in
, ref
или out
внешней области определения.- В пределах блока анонимного метода нельзя получить доступ к небезопасному коду.
- Анонимные методы не допускаются в левой части оператора
is
.- Локальные переменные и параметры, определённые в той же области, что и анонимный метод, называются внешними переменными анонимного метода:
int n = 0;Ссылка на внешнюю переменную
Del d = Delegate() {System.Console.WriteLine ("Copy #: {0}", ++n); };
n
захватывается при создании делегата. В отличие от локальных переменных, время жизни захваченной переменной увеличивается до тех пор, пока делегаты, ссылающиеся на анонимные методы, не будут подходить для сборки мусора.Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/anonymous-methods
День сто тридцать пятый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
18. В чём разница между Array и ArrayList в C#?
Ключевые методы
1.
2.
3.
4.
5.
6.
7.
8.
Преимущества
1. Не хранит определённые типы данных, хранит все как объекты.
2. Нет необходимости явно выделять и освобождать место для хранения данных.
3. Имеет явные методы сортировки.
4. Может вставлять и удалять элементы между позициями.
5. Может хранить объекты.
Недостатки
1. Не является строго типизированным. Нужно выполнять приведение типов при извлечении контента. Это сказывается на производительности.
2. Использует для хранения LinkedList, поэтому для вставки или удаления по определенной позиции выполняется обход всех адресов хранения.
3. Может приводить к ошибке времени выполнения, если реальный тип элемента не будет совпадать с желаемым.
Разница между Array и ArrayList
Array
- Использует векторный массив для хранения элементов
- Размер массива должен быть определен до использования.
- Хранит данные определенного типа.
- Нет необходимости выполнять приведение типов.
- Нет методов для сортировки и вставки/удаления элементов.
ArrayList
- Использует связанный список для хранения элементов.
- Нет необходимости указывать размер хранилища.
- Хранить все элементы как объекты.
- Необходимо выполнять приведение типов.
- Имеет методы для вставки, удаления, сортировки и поиска элементов.
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по C#
18. В чём разница между Array и ArrayList в C#?
ArrayList
- это динамический массив. Он хранит значения как объекты и изменяет размер места хранения по мере необходимости.Ключевые методы
1.
BinarySearch
- возвращает позицию объекта поиска в виде целочисленного значения.2.
Insert
- вставляет элемент в указанное место по индексу.3.
InsertRange
- вставляет элементы как отдельные объекты в указанное место.4.
Remove
- удаляет первое появление данного объекта.5.
RemoveAt
- удаляет элемент по индексу.6.
RemoveRange
- удаляет набор элементов из указанного диапазона.7.
Sort
- выполняет сортировку элементов в порядке возрастания.8.
Reverse
– упорядочивает элементы в обратном порядке.Преимущества
1. Не хранит определённые типы данных, хранит все как объекты.
2. Нет необходимости явно выделять и освобождать место для хранения данных.
3. Имеет явные методы сортировки.
4. Может вставлять и удалять элементы между позициями.
5. Может хранить объекты.
Недостатки
1. Не является строго типизированным. Нужно выполнять приведение типов при извлечении контента. Это сказывается на производительности.
2. Использует для хранения LinkedList, поэтому для вставки или удаления по определенной позиции выполняется обход всех адресов хранения.
3. Может приводить к ошибке времени выполнения, если реальный тип элемента не будет совпадать с желаемым.
Разница между Array и ArrayList
Array
- Использует векторный массив для хранения элементов
- Размер массива должен быть определен до использования.
- Хранит данные определенного типа.
- Нет необходимости выполнять приведение типов.
- Нет методов для сортировки и вставки/удаления элементов.
ArrayList
- Использует связанный список для хранения элементов.
- Нет необходимости указывать размер хранилища.
- Хранить все элементы как объекты.
- Необходимо выполнять приведение типов.
- Имеет методы для вставки, удаления, сортировки и поиска элементов.
Источник: https://www.c-sharpcorner.com
День сто тридцать шестой. #ЗаметкиНаПолях
Лямбда-выражения. Начало
Лямбда-выражение - это блок кода (выражение или блок операторов), который обрабатывается как объект. Он может быть передан в качестве аргумента методам, а также может быть возвращен методом.
Варианты использования:
- Код для исполнения асинхронным методом, таким как Task.Run(Action).
- Выражения для запросов LINQ.
- Создание деревьев выражений.
Лямбда-выражения - это код, который может быть представлен как делегат или как дерево выражений, которое компилируется в делегат. Конкретный тип делегата лямбда-выражения зависит от его параметров и возвращаемого значения. Лямбда-выражения, которые не возвращают значение, соответствуют конкретному делегату
Лямбда-выражение использует =>, оператор лямбда-объявления, чтобы отделить список параметров лямбды от его исполняемого кода. Чтобы создать лямбда-выражение, указываются входные параметры (если они есть) слева от оператора лямбда-выражения, и само выражение с другой стороны. Например, однострочное лямбда-выражение
Это выражение можно назначить:
- типу делегата:
Все ограничения, которые применяются к анонимным методам (см. https://t.iss.one/NetDeveloperDiary/163), также применяются к лямбда-выражениям.
Продолжение следует…
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
Лямбда-выражения. Начало
Лямбда-выражение - это блок кода (выражение или блок операторов), который обрабатывается как объект. Он может быть передан в качестве аргумента методам, а также может быть возвращен методом.
Варианты использования:
- Код для исполнения асинхронным методом, таким как Task.Run(Action).
- Выражения для запросов LINQ.
- Создание деревьев выражений.
Лямбда-выражения - это код, который может быть представлен как делегат или как дерево выражений, которое компилируется в делегат. Конкретный тип делегата лямбда-выражения зависит от его параметров и возвращаемого значения. Лямбда-выражения, которые не возвращают значение, соответствуют конкретному делегату
Action
с соответствующим количеством параметров. Лямбда-выражения, которые возвращают значение, соответствуют конкретному делегату Func
с соответствующим количеством параметров. Например, лямбда-выражение, которое имеет два параметра, но не возвращает значения, соответствует делегату Action<T1, T2>
. Лямбда-выражение с одним параметром, возвращающее значение, соответствует делегату Func<T, TResult>
.Лямбда-выражение использует =>, оператор лямбда-объявления, чтобы отделить список параметров лямбды от его исполняемого кода. Чтобы создать лямбда-выражение, указываются входные параметры (если они есть) слева от оператора лямбда-выражения, и само выражение с другой стороны. Например, однострочное лямбда-выражение
x => x * x
указывает параметр с именем x
и возвращает значение x
в квадрате. Это выражение можно назначить:
- типу делегата:
Func<int, int> square = x => x * x;- дереву выражений:
Console.WriteLine(square(5));
// вывод: 25
using System.Linq.Expressions;- аргументу метода:
Expression<Func<int, int>> exp = x => x * x;
Console.WriteLine(exp);
// вывод: x => (x * x)
int[] numbers = { 2, 3, 4, 5 };При использовании синтаксиса методов для вызова
var squaredNumbers = numbers.Select(x => x * x);
Console.WriteLine(string.Join(" ", squaredNumbers));
// вывод: 4 9 16 25
Enumerable.Select
в классе System.Linq.Enumerable
(как в LINQ to Objects и LINQ to XML) его параметр является делегатом типа Func<T, TResult>
. Лямбда-выражение является наиболее удобным способом создания этого делегата. При вызове метода Queryable.Select
в классе System.Linq.Queryable
(как в LINQ to SQL) тип параметра представляет собой дерево выражений Expression<Func <TSource, TResult>>
. Опять же, лямбда-выражение - это краткий способ построения этого дерева выражений. Лямбда-выражения позволяют вызовам Select выглядеть одинаково, хотя на самом деле тип объекта, созданного из них, отличается.Все ограничения, которые применяются к анонимным методам (см. https://t.iss.one/NetDeveloperDiary/163), также применяются к лямбда-выражениям.
Продолжение следует…
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
👍1
День сто тридцать седьмой. #ЗаметкиНаПолях
Лямбда-выражения. Продолжение
Выражения лямбды
Лямбда-выражение с выражением справа от оператора => называется выражением лямбда. Выражения лямбда широко используются при построении деревьев выражений. Выражение лямбда возвращает результат выражения и имеет следующую базовую форму:
Если входные параметры отсутствуют, используются пустые скобки:
Тело лямбда-выражения может состоять из вызова метода. Однако если вы создаете деревья выражений, которые оцениваются вне контекста общеязыковой среды выполнения .NET, например, в SQL Server, вы не должны использовать вызовы методов в лямбда-выражениях. Методы не будут иметь никакого значения вне контекста общеязыковой среды выполнения .NET.
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
Лямбда-выражения. Продолжение
Выражения лямбды
Лямбда-выражение с выражением справа от оператора => называется выражением лямбда. Выражения лямбда широко используются при построении деревьев выражений. Выражение лямбда возвращает результат выражения и имеет следующую базовую форму:
(входные параметры) => выражениеСкобки необязательны, только если лямбда имеет один входной параметр, в противном случае они требуются.
Если входные параметры отсутствуют, используются пустые скобки:
Action line = () => Console.WriteLine();Два или более входных параметров разделяются запятыми в скобках:
Func<int, int, bool> testForEquality = (x, y) => x == y;Иногда компилятор не может определить типы входных параметров. Вы можете указать типы явно:
Func<int, string, bool> isTooLong = (int x, string s) => s.Length > x;Типы входных параметров должны либо все указываться явно, либо не указываться вообще, иначе будет выброшено исключение компилятора CS0748.
Тело лямбда-выражения может состоять из вызова метода. Однако если вы создаете деревья выражений, которые оцениваются вне контекста общеязыковой среды выполнения .NET, например, в SQL Server, вы не должны использовать вызовы методов в лямбда-выражениях. Методы не будут иметь никакого значения вне контекста общеязыковой среды выполнения .NET.
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
День сто тридцать восьмой. #ЗаметкиНаПолях
Лямбда-выражения. Продолжение
Лямбды операторов
Лямбда операторов напоминает лямбда-выражение, за исключением того, что оператор(ы) заключен(ы) в фигурные скобки:
Асинхронные лямбды
Вы можете легко создавать лямбда-выражения и операторы, которые включают асинхронную обработку, используя ключевые слова
Начиная с C# 7.0, язык поддерживает кортежи как аргументы или возвращаемые значения лямбда-выражений. В некоторых случаях компилятор C# использует определение типа для определения типов компонентов кортежа.
Вы определяете кортеж, заключая в скобки список его компонентов, разделенных запятыми. В следующем примере используется кортеж с тремя компонентами для передачи последовательности чисел в лямбда-выражение, которое удваивает каждое значение и возвращает кортеж с тремя компонентами, который содержит результат умножения.
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
Лямбда-выражения. Продолжение
Лямбды операторов
Лямбда операторов напоминает лямбда-выражение, за исключением того, что оператор(ы) заключен(ы) в фигурные скобки:
(входные параметры) => {оператор;}Тело оператора лямбда может состоять из любого числа операторов; однако на практике их обычно не более двух или трех:
Action<string> greet = name =>Лямбды операторов, как и анонимные методы, не могут быть использованы для создания деревьев выражений.
{
string greeting = $"Hello {name}!";
Console.WriteLine(greeting);
};
greet("World");
// Вывод:
// Hello World!
Асинхронные лямбды
Вы можете легко создавать лямбда-выражения и операторы, которые включают асинхронную обработку, используя ключевые слова
async
и await
. В следующем примере Windows Forms содержится обработчик событий, который вызывает и ожидает асинхронный метод SomeAsyncMethod
:public Form1()Обработчик нажатия на кнопку можно добавить с помощью асинхронной лямбды:
{
InitializeComponent();
button1.Click += button1_Click;
}
private async void button1_Click(object sender, EventArgs e)
{
await SomeAsyncMethod();
}
private async Task SomeAsyncMethod(){…}
public Form1()Лямбда-выражения и кортежи
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
await SomeAsyncMethod();
};
}
Начиная с C# 7.0, язык поддерживает кортежи как аргументы или возвращаемые значения лямбда-выражений. В некоторых случаях компилятор C# использует определение типа для определения типов компонентов кортежа.
Вы определяете кортеж, заключая в скобки список его компонентов, разделенных запятыми. В следующем примере используется кортеж с тремя компонентами для передачи последовательности чисел в лямбда-выражение, которое удваивает каждое значение и возвращает кортеж с тремя компонентами, который содержит результат умножения.
Func<(int, int, int), (int, int, int)> doubleThem = ns => (2 * ns.Item1, 2 * ns.Item2, 2 * ns.Item3);Обычно поля кортежа называются
var numbers = (2, 3, 4);
var doubles = doubleThem(numbers);
Console.WriteLine($"Кортеж чисел {numbers} удвоен: {doubles}");
// Вывод:
// Кортеж чисел (2, 3, 4) удвоен: (4, 6, 8)
Item1
, Item2
, и т.п. Но можно задать им имена:Func<(int n1, int n2, int n3), (int, int, int)> doubleThem = ns => (2 * ns.n1, 2 * ns.n2, 2 * ns.n3);Продолжение следует…
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
День сто тридцать девятый. #ЗаметкиНаПолях
Лямбда-выражения. Окончание
Вывод типа в лямбда-выражениях
При написании лямбда-выражений часто нет необходимости указывать тип для входных параметров, поскольку компилятор может вывести тип на основе тела лямбда выражения, типов параметров и других факторов, описанных в спецификации языка C#. Для большинства стандартных операторов запросов первым вводом является тип элементов в исходной последовательности. Если вы запрашиваете
- Лямбда должна содержать то же количество параметров, что и тип делегата.
- Каждый входной параметр в лямбда-выражении должен быть неявно преобразован в соответствующий ему параметр делегата.
- Возвращаемое значение лямбды (если оно есть) должно быть неявно конвертируемым в возвращаемый тип делегата.
Замечание: лямбда-выражения сами по себе не имеют типа, потому что общая система типов не имеет внутреннего понятия «лямбда-выражение». Однако иногда удобно неформально говорить о «типе» лямбда-выражения. В этих случаях тип относится к типу делегата или типу выражения, в которые преобразуется лямбда-выражение.
Область видимости переменных в лямбда-выражениях
Лямбда-выражение может ссылаться на внешние переменные (см. пост про анонимные методы https://t.iss.one/NetDeveloperDiary/163), которые находятся внутри метода, определяющего лямбда-выражение, или в типе, содержащем лямбда-выражение. Переменные, захваченные таким образом, сохраняются для использования в лямбда-выражении, даже они иначе вышли бы из области видимости и подлежали бы сборке мусора.
Правила области видимости в лямбда-выражениях:
- Внешняя переменная должна быть явно определена, прежде чем она сможет быть использована в лямбда-выражении.
- Перехваченная переменная не будет собираться мусором до тех пор, пока делегат, ссылающийся на нее, не станет пригодным для сборки мусора.
- Переменные, введенные в лямбда-выражении, не видны во включающем выражение методе.
- Лямбда-выражение не может напрямую захватить параметр
- Оператор return в лямбда-выражении не приводит к возврату включающего его метода.
- Лямбда-выражение не может содержать оператор
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
Лямбда-выражения. Окончание
Вывод типа в лямбда-выражениях
При написании лямбда-выражений часто нет необходимости указывать тип для входных параметров, поскольку компилятор может вывести тип на основе тела лямбда выражения, типов параметров и других факторов, описанных в спецификации языка C#. Для большинства стандартных операторов запросов первым вводом является тип элементов в исходной последовательности. Если вы запрашиваете
IEnumerable<Customer>
, то входная переменная приводится к объекту Customer
, что означает, что у вас есть доступ к её методам и свойствам:customers.Where(c => c.City == "London");Общие правила для вывода типа:
- Лямбда должна содержать то же количество параметров, что и тип делегата.
- Каждый входной параметр в лямбда-выражении должен быть неявно преобразован в соответствующий ему параметр делегата.
- Возвращаемое значение лямбды (если оно есть) должно быть неявно конвертируемым в возвращаемый тип делегата.
Замечание: лямбда-выражения сами по себе не имеют типа, потому что общая система типов не имеет внутреннего понятия «лямбда-выражение». Однако иногда удобно неформально говорить о «типе» лямбда-выражения. В этих случаях тип относится к типу делегата или типу выражения, в которые преобразуется лямбда-выражение.
Область видимости переменных в лямбда-выражениях
Лямбда-выражение может ссылаться на внешние переменные (см. пост про анонимные методы https://t.iss.one/NetDeveloperDiary/163), которые находятся внутри метода, определяющего лямбда-выражение, или в типе, содержащем лямбда-выражение. Переменные, захваченные таким образом, сохраняются для использования в лямбда-выражении, даже они иначе вышли бы из области видимости и подлежали бы сборке мусора.
Правила области видимости в лямбда-выражениях:
- Внешняя переменная должна быть явно определена, прежде чем она сможет быть использована в лямбда-выражении.
- Перехваченная переменная не будет собираться мусором до тех пор, пока делегат, ссылающийся на нее, не станет пригодным для сборки мусора.
- Переменные, введенные в лямбда-выражении, не видны во включающем выражение методе.
- Лямбда-выражение не может напрямую захватить параметр
in
, ref
или out
из включающего его метода.- Оператор return в лямбда-выражении не приводит к возврату включающего его метода.
- Лямбда-выражение не может содержать оператор
goto
, break
или continue
, если цель этого оператора находится вне блока лямбда-выражения, и наоборот.Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
День сто сороковой. #ЗаметкиНаПолях
Коллекции в C#
1. Словарь Dictionary<TKey, TValue>
Словарь - это тип коллекции, который полезен, когда вам нужен быстрый поиск по ключам. Например, у вас есть список клиентов, и в рамках задачи вам нужно быстро найти клиента по его ID (или другому уникальному ключу). В списке поиск элемента линейный, и стоимость этой операции составляет O(n). Однако при использовании словаря поиск выполняется стоимостью O(1), т.е. независимо от того, насколько велик словарь, время поиска остается относительно постоянным.
При хранении или извлечении объекта в словаре необходимо указать ключ. Ключ - это значение, которое однозначно идентифицирует объект и не может быть
Для создания словаря нужно указать тип ключей и значений. Например, для словаря клиентов:
Источник: https://programmingwithmosh.com/net/csharp-collections/
Коллекции в C#
1. Словарь Dictionary<TKey, TValue>
Словарь - это тип коллекции, который полезен, когда вам нужен быстрый поиск по ключам. Например, у вас есть список клиентов, и в рамках задачи вам нужно быстро найти клиента по его ID (или другому уникальному ключу). В списке поиск элемента линейный, и стоимость этой операции составляет O(n). Однако при использовании словаря поиск выполняется стоимостью O(1), т.е. независимо от того, насколько велик словарь, время поиска остается относительно постоянным.
При хранении или извлечении объекта в словаре необходимо указать ключ. Ключ - это значение, которое однозначно идентифицирует объект и не может быть
null
. Например, чтобы сохранить объект Customer
в словаре, вы можете использовать CustomerID
в качестве ключа.Для создания словаря нужно указать тип ключей и значений. Например, для словаря клиентов:
var dictionary = new Dictionary<int, Customer>();Наиболее полезные методы и свойства:
dictionary.Add(customer.Id, customer);
…
// Получаем клиента с ID 1234
var customer = dictionary[1234];
// Удаление элемента по ключуПочему поиск в словаре так быстр? Словарь хранит объекты в массиве, но в отличие от списка, в котором объекты добавляются в конец массива (или по указанному индексу), индекс в словаре вычисляется с использованием хеш-функции. При сохранении объекта в словаре, вычисляется хеш ключа с помощью функции
dictionary.Remove(1);
// Очистка словаря
dictionary.Clear();
// Количество элементов
var count = dictionary.Count;
// Проверка на вхождение ключа
var containsKey = dictionary.ContainsKey(1);
// Проверка на вхождение значения
var containsValue = dictionary.ContainsValue(customer1);
// Итерация по ключам
foreach (var key in dictionary.Keys)
Console.WriteLine(dictionary[key]);
// Итерация по значениям
foreach (var value in dictionary.Values)
Console.WriteLine(value);
// Итерация по парам ключ-значение
foreach (var keyValuePair in dictionary)
{
Console.WriteLine(keyValuePair.Key);
Console.WriteLine(keyValuePair.Value);
}
GetHashCode
. Затем хэш корректируется под размер массива, чтобы вычислить индекс. При поиске объекта по ключу, метод GetHashCode
снова используется для вычисления хеша и индекса. Поэтому, в отличие от списков, поиск объекта в словаре не требует сканирования каждого объекта и независимо от того, насколько велик словарь, он останется чрезвычайно быстрым.Источник: https://programmingwithmosh.com/net/csharp-collections/
День сто сорок первый. #ЗаметкиНаПолях
Коллекции в C#
2. HashSet<T>
Создание и использование:
- Инициализация:
- Пересечение множеств (изменяет hashSet):
- Симметричная разница (изменяет hashSet), элементы из hashSet или из another, но не из обоих:
Коллекции в C#
2. HashSet<T>
HashSet
представляет набор уникальных элементов, как математическое множество (например, {1, 2, 3}
). Набор не может содержать дубликаты, а порядок элементов не имеет значения, т.е. {1, 2, 3}
и {3, 2, 1}
равны.HashSet
используется, когда вам нужен быстрый поиск в наборе уникальных элементов. Например, при обработке списка заказов для каждого заказа вам нужно быстро проверить, входит ли код поставщика в список корректных кодов.HashSet
, похож на Dictionary
, представляет собой коллекцию на основе хеша, поэтому поиск выполняется очень быстро за время O(1). Но, в отличие от словаря, он хранит только значения без ключей. Таким образом, каждый объект должен быть уникальным, и это определяется по GetHashCode
. Т.е., если вы собираетесь хранить пользовательские типы в наборе, вам необходимо переопределить методы GetHashCode
и Equals
в вашем типе.Создание и использование:
- Инициализация:
var hashSet = new HashSet<int>() { 1, 2, 3 };- Добавление:
hashSet.Add(4);- Удаление:
hashSet.Remove(3);- Очистка:
hashSet.Clear();- Проверка наличия элемента:
var contains = hashSet.Contains(1);- Количество элементов:
var count = hashSet.Count;
HashSet
предоставляет набор математических операций для работы с множествами. Следующие методы имеют аналоги в LINQ для любых коллекций IEnumerable<T>:- Пересечение множеств (изменяет hashSet):
hashSet.IntersectWith(another);- Объединение множеств (изменяет hashSet):
hashSet.UnionWith(another);- Удаляет все элементы another из hashSet:
hashSet.ExceptWith(another);Следующие методы НЕ имеют аналогов в LINQ для обычных коллекций:
- Симметричная разница (изменяет hashSet), элементы из hashSet или из another, но не из обоих:
hashSet.SymmetricExceptWith(another);- Является ли hashSet надмножеством another:
var isSupersetOf = hashSet.IsSupersetOf(another);- Является ли hashSet строгим надмножеством another:
var isSupersetOf = hashSet.IsProperSupersetOf(another);- Является ли hashSet подмножеством another:
var isSubsetOf = hashSet.IsSubsetOf(another);- Является ли hashSet строгим подмножеством another:
var isSubsetOf = hashSet.IsProperSubsetOf(another);- Содержит ли hashSet те же элементы, что и another:
var equals = hashSet.SetEquals(another);- Есть ли у hashSet и another одинаковые элементы:
var overlaps = hashSet.Overlaps(another);Источник: https://programmingwithmosh.com/net/csharp-collections/
День сто сорок второй. #ЧтоНовенького
Visual Studio 2019 версии 16.2
Вышло превью Visual Studio 2019 версии 16.2. Версия доступна для загрузки с VisualStudio.com, или, если у вас отмечена установка превью версий, просто щелкните значок уведомления в Visual Studio для обновления.
Поддержка Microsoft Edge Insider
Теперь Visual Studio позволяет отлаживать JavaScript в новом браузере Microsoft Edge Insider для проектов ASP.NET и ASP.NET Core. Для этого просто установите браузер, установите точку останова в JavaScript приложении и начните сеанс отладки. Visual Studio запустит новое окно браузера с включенной отладкой, что позволит вам шагать по коду JavaScript в Visual Studio (см. картинку выше).
Visual Studio 2019 версии 16.2
Вышло превью Visual Studio 2019 версии 16.2. Версия доступна для загрузки с VisualStudio.com, или, если у вас отмечена установка превью версий, просто щелкните значок уведомления в Visual Studio для обновления.
Поддержка Microsoft Edge Insider
Теперь Visual Studio позволяет отлаживать JavaScript в новом браузере Microsoft Edge Insider для проектов ASP.NET и ASP.NET Core. Для этого просто установите браузер, установите точку останова в JavaScript приложении и начните сеанс отладки. Visual Studio запустит новое окно браузера с включенной отладкой, что позволит вам шагать по коду JavaScript в Visual Studio (см. картинку выше).
Улучшения помощников
- «По просьбам трудящихся» возвращена команда Sort Usings, и она отделена Remove Usings. Sort Usings можно найти в меню Edit > IntelliSense.
- Добавлена возможность преобразовывать операторы switch в выражения. Поскольку выражения-переключатели являются новой функцией C# 8.0, необходимо убедиться, что вы используете самую последнюю версию языка. Поместите курсор на ключевое слово switch, нажмите Ctrl+., в выпадающем меню Quick Actions and Refactorings выберите Convert switch statement to expression.
Улучшение установщика Visual Studio
Установщик Visual Studio теперь будет лучше определять размер свободного места в зависимости от того, что вы уже установили на своем компьютере. Это означает, что, если требуемый объем пространства больше, чем доступно, установка отменяется.
Источник: https://devblogs.microsoft.com/visualstudio/visual-studio-2019-version-16-2-preview-2/
- «По просьбам трудящихся» возвращена команда Sort Usings, и она отделена Remove Usings. Sort Usings можно найти в меню Edit > IntelliSense.
- Добавлена возможность преобразовывать операторы switch в выражения. Поскольку выражения-переключатели являются новой функцией C# 8.0, необходимо убедиться, что вы используете самую последнюю версию языка. Поместите курсор на ключевое слово switch, нажмите Ctrl+., в выпадающем меню Quick Actions and Refactorings выберите Convert switch statement to expression.
Улучшение установщика Visual Studio
Установщик Visual Studio теперь будет лучше определять размер свободного места в зависимости от того, что вы уже установили на своем компьютере. Это означает, что, если требуемый объем пространства больше, чем доступно, установка отменяется.
Источник: https://devblogs.microsoft.com/visualstudio/visual-studio-2019-version-16-2-preview-2/
День сто сорок третий. #ЗаметкиНаПолях
Коллекции в C#
3. Стек
Стек - это тип коллекции с поведением «последний пришел - первым вышел» (LIFO). Мы часто используем стеки в сценариях, где нам нужно предоставить пользователю способ вернуться назад. Подумайте о своем браузере. Когда вы переходите на разные веб-сайты, эти адреса, которые вы посещаете, помещаются в стек. Затем, когда вы нажимаете кнопку «Назад», элемент в стеке (который представляет текущий адрес в браузере) извлекается, и теперь мы можем получить последний адрес, который вы посетили, из элемента в стеке. Функция отмены в приложениях также реализована с использованием стека.
Использование стека:
Источник: https://programmingwithmosh.com/net/csharp-collections/
Коллекции в C#
3. Стек
Стек - это тип коллекции с поведением «последний пришел - первым вышел» (LIFO). Мы часто используем стеки в сценариях, где нам нужно предоставить пользователю способ вернуться назад. Подумайте о своем браузере. Когда вы переходите на разные веб-сайты, эти адреса, которые вы посещаете, помещаются в стек. Затем, когда вы нажимаете кнопку «Назад», элемент в стеке (который представляет текущий адрес в браузере) извлекается, и теперь мы можем получить последний адрес, который вы посетили, из элемента в стеке. Функция отмены в приложениях также реализована с использованием стека.
Использование стека:
var stack = new Stack<string>();Внутренне стек реализован с использованием массива. Поскольку массивы в C# имеют фиксированный размер, когда вы помещаете элементы в стек, может потребоваться увеличить его емкость путем выделения большего массива и копирования существующих элементов в новый массив. Если выделения не требуется, операция
// Размещение элемента в стеке
stack.Push("https://www.google.com");
// Проверка вхождения элемента
var contains = stack.Contains("https://www.google.com");
// Извлечение элемента из вершины стека
var top = stack.Pop();
// Просмотр элемента из вершины стека без извлечения
var top = stack.Peek();
// Количество элементов
var count = stack.Count;
// Очистка
stack.Clear();
Push
выполняется за время O(1); в противном случае, при условии, что в стеке есть n элементов, все эти элементы необходимо скопировать в новый массив. Это приводит к выполнению операции за время O(n). Pop
– за время O(1). Contains
- O(n).Источник: https://programmingwithmosh.com/net/csharp-collections/
День сто сорок четвёртый. #ЗаметкиНаПолях
Коллекции в C#
4. Очередь
Очередь представляет коллекцию с поведением «первым пришел - первым обслужен» (FIFO). Очереди используются, когда нужно обрабатывать элементы по мере их поступления.
Основные операции:
-
-
-
Ёмкость
Использование:
используются
Источники:
- https://programmingwithmosh.com/net/csharp-collections/
- https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.queue
Коллекции в C#
4. Очередь
Очередь представляет коллекцию с поведением «первым пришел - первым обслужен» (FIFO). Очереди используются, когда нужно обрабатывать элементы по мере их поступления.
Queue<T>
реализует обобщённую очередь в виде циклического массива. Объекты добавляются с одного конца и извлекаются с другого. Очереди и стеки полезны, когда вам нужно временное хранилище информации (когда вы можете отказаться от элемента после получения его значения). Используйте очередь, если вам нужен доступ к информации в том же порядке, в котором она хранится в коллекции. Основные операции:
-
Enqueue
: добавление элемента в конец очереди;-
Dequeue
: извлечение элемента из начала очереди;-
Peek
: просмотр элемента из начала очереди без извлечения.Ёмкость
Queue<T>
- это количество элементов, которые она может содержать. По мере добавления элементов ёмкость автоматически увеличивается при необходимости путем перераспределения внутреннего массива. Емкость можно уменьшить, вызвав метод TrimExcess.Queue<T>
допускает значение NULL
для ссылочных типов и допускает дублирование элементов.Использование:
var queue = new Queue<string>();Если нужен одновременный доступ к коллекции из нескольких потоков,
// добавление
queue.Enqueue("transaction1");
// проверка вхождения элемента
var contains = queue.Contains("transaction1");
// извлечение
var front = queue.Dequeue();
// просмотр первого элемента
var top = queue.Peek();
// очистка очереди
queue.Clear();
// количество элементов
var count = queue.Count;
используются
ConcurrentQueue<T>
для очереди или ConcurrentStack<T>
для стека.Источники:
- https://programmingwithmosh.com/net/csharp-collections/
- https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.queue