День сто десятый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
1. Что такое C#?
C# - это язык программирования. Он был создан Microsoft в 2000 году для предоставления современного языка программирования общего назначения, который можно использовать для разработки всех видов программного обеспечения для различных платформ, включая Windows, Web и Mobile, используя только один язык программирования. Сегодня C# является одним из самых популярных языков программирования в мире. Миллионы разработчиков программного обеспечения используют C# для создания всех видов программного обеспечения.
C# является основным языком для создания программных приложений Microsoft .NET. Разработчики могут создавать практически все виды программного обеспечения с использованием C#, включая приложения пользовательского интерфейса Windows, консольные приложения, серверные службы, облачные API, веб-службы, элементы управления и библиотеки, серверные приложения, веб-приложения, приложения для iOS и Android, ПО искусственного интеллекта и машинного обучения, а также блокчейн приложений.
С помощью IDE Visual Studio C# обеспечивает быструю разработку приложений. C# - это современный, объектно-ориентированный, простой, универсальный и ориентированный на производительность язык программирования. C# разработан на основе лучших функций и вариантов использования нескольких языков программирования, включая C++, Java, Pascal и SmallTalk.
Синтаксис C# похож на C++. Библиотека .NET и C# похожа на Java. C# поддерживает современные возможности объектно-ориентированного языка программирования, включая абстракцию, инкапсуляцию, полиморфизм и наследование. C# является строго типизированным языком, и большинство типов наследуются от класса Object.
C# поддерживает концепции классов и объектов. Классы имеют такие элементы, как поля, свойства, события и методы. C# универсален, современен и поддерживает современные потребности программирования. С самого начала язык C# прошел различные обновления. В этом году ожидается релиз C# версии 8.0.
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по C#
1. Что такое C#?
C# - это язык программирования. Он был создан Microsoft в 2000 году для предоставления современного языка программирования общего назначения, который можно использовать для разработки всех видов программного обеспечения для различных платформ, включая Windows, Web и Mobile, используя только один язык программирования. Сегодня C# является одним из самых популярных языков программирования в мире. Миллионы разработчиков программного обеспечения используют C# для создания всех видов программного обеспечения.
C# является основным языком для создания программных приложений Microsoft .NET. Разработчики могут создавать практически все виды программного обеспечения с использованием C#, включая приложения пользовательского интерфейса Windows, консольные приложения, серверные службы, облачные API, веб-службы, элементы управления и библиотеки, серверные приложения, веб-приложения, приложения для iOS и Android, ПО искусственного интеллекта и машинного обучения, а также блокчейн приложений.
С помощью IDE Visual Studio C# обеспечивает быструю разработку приложений. C# - это современный, объектно-ориентированный, простой, универсальный и ориентированный на производительность язык программирования. C# разработан на основе лучших функций и вариантов использования нескольких языков программирования, включая C++, Java, Pascal и SmallTalk.
Синтаксис C# похож на C++. Библиотека .NET и C# похожа на Java. C# поддерживает современные возможности объектно-ориентированного языка программирования, включая абстракцию, инкапсуляцию, полиморфизм и наследование. C# является строго типизированным языком, и большинство типов наследуются от класса Object.
C# поддерживает концепции классов и объектов. Классы имеют такие элементы, как поля, свойства, события и методы. C# универсален, современен и поддерживает современные потребности программирования. С самого начала язык C# прошел различные обновления. В этом году ожидается релиз C# версии 8.0.
Источник: https://www.c-sharpcorner.com
День сто одиннадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
2. Что такое объект в C#?
C# - это объектно-ориентированный язык программирования. Классы являются основой C#. Класс - это шаблон, который определяет, как будет выглядеть структура данных, как данные будут храниться, управляться и передаваться. У класса есть поля, свойства, методы и другие члены.
Классы – концептуальные понятия, а объекты реальные. Объекты создаются как экземпляры класса. Класс может иметь столько экземпляров, сколько необходимо. Класс определяет тип объекта. Объекты хранят реальные значения в памяти компьютера.
Любая сущность реального мира, которая может иметь некоторые характеристики или которая может выполнять какую-либо работу, называется объектом или экземпляром, т. е. копией сущности на языке программирования.
Например, нам нужно создать программу, которая занимается автомобилями. Нам нужно создать сущность для автомобиля. Давайте назовем это классом Автомобиль. Автомобиль имеет четыре свойства: модель, тип, цвет и размер.
Чтобы представить автомобиль в программировании, мы можем создать класс
Например, Honda Civic является экземпляром автомобиля. В программировании Honda Civic - это объект. Свойства
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по C#
2. Что такое объект в C#?
C# - это объектно-ориентированный язык программирования. Классы являются основой C#. Класс - это шаблон, который определяет, как будет выглядеть структура данных, как данные будут храниться, управляться и передаваться. У класса есть поля, свойства, методы и другие члены.
Классы – концептуальные понятия, а объекты реальные. Объекты создаются как экземпляры класса. Класс может иметь столько экземпляров, сколько необходимо. Класс определяет тип объекта. Объекты хранят реальные значения в памяти компьютера.
Любая сущность реального мира, которая может иметь некоторые характеристики или которая может выполнять какую-либо работу, называется объектом или экземпляром, т. е. копией сущности на языке программирования.
Например, нам нужно создать программу, которая занимается автомобилями. Нам нужно создать сущность для автомобиля. Давайте назовем это классом Автомобиль. Автомобиль имеет четыре свойства: модель, тип, цвет и размер.
Чтобы представить автомобиль в программировании, мы можем создать класс
Car
с четырьмя свойствами: Model
, Type
, Color
и Size
. Они называются членами класса. Класс имеет несколько типов членов: конструкторы, поля, свойства, методы, делегаты и события. Член класса может быть приватным, защищенным и открытым. Поскольку эти свойства автомобиля могут быть доступны извне класса, они могут быть открытыми.Например, Honda Civic является экземпляром автомобиля. В программировании Honda Civic - это объект. Свойства
Model
, Type
, Color
, and Size
автомобиля Honda Civic: Civic, Honda, Red, 4.Источник: https://www.c-sharpcorner.com
День сто двенадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
3. Что Такое Управляемый и Неуправляемый Код?
Управляемый Код
Это код, разработанный с использованием платформы .NET и ее поддерживаемых языков программирования, таких как C# или VB.NET. Управляемый код напрямую выполняется общеязыковой средой исполнения (CLR или Runtime), а его жизненный цикл, включая создание объектов, выделение памяти и удаление объектов, управляется средой исполнения. Любой код, написанный внутри .NET Framework или на языке, поддерживаемом .NET Framework, является управляемым кодом.
Неуправляемый Код
Код, разработанный за пределами .NET Framework, называется неуправляемым кодом.
Приложения, которые не работают под управлением CLR, считаются неуправляемыми. Такие языки, как C или C++ или Visual Basic, неуправляемые. Создание, выполнение и удаление объектов в неуправляемом коде выполняется программистами напрямую. Если программисты пишут плохой код, это может привести к утечкам памяти и нежелательному распределению ресурсов.
.NET Framework предоставляет механизм работы с неуправляемым кодом, который будет использоваться в управляемом коде, и наоборот. Процесс выполняется с помощью классов-обёрток.
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по C#
3. Что Такое Управляемый и Неуправляемый Код?
Управляемый Код
Это код, разработанный с использованием платформы .NET и ее поддерживаемых языков программирования, таких как C# или VB.NET. Управляемый код напрямую выполняется общеязыковой средой исполнения (CLR или Runtime), а его жизненный цикл, включая создание объектов, выделение памяти и удаление объектов, управляется средой исполнения. Любой код, написанный внутри .NET Framework или на языке, поддерживаемом .NET Framework, является управляемым кодом.
Неуправляемый Код
Код, разработанный за пределами .NET Framework, называется неуправляемым кодом.
Приложения, которые не работают под управлением CLR, считаются неуправляемыми. Такие языки, как C или C++ или Visual Basic, неуправляемые. Создание, выполнение и удаление объектов в неуправляемом коде выполняется программистами напрямую. Если программисты пишут плохой код, это может привести к утечкам памяти и нежелательному распределению ресурсов.
.NET Framework предоставляет механизм работы с неуправляемым кодом, который будет использоваться в управляемом коде, и наоборот. Процесс выполняется с помощью классов-обёрток.
Источник: https://www.c-sharpcorner.com
День сто тринадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
4. Чем отличается интерфейс от абстрактного класса в C#?
Это, вероятно, самый часто задаваемый вопрос в мире .Net. Теоретически между абстрактным классом и интерфейсом есть 5 отличий, которые перечислены ниже:
1. Класс может реализовывать любое количество интерфейсов, но дочерний класс может наследовать только от одного абстрактного класса.
2. Абстрактный класс может иметь неабстрактные (конкретные) методы, в то время как в случае интерфейса все методы должны быть абстрактными. (Начиная с C# 8 допускается реализация по умолчанию интерфейсных методов).
3. Абстрактный класс может объявлять или использовать любые переменные, в то время как интерфейсу это запрещено. То есть следующий код приведёт к ошибке компиляции "Interfaces cannot contain fields" ("Интерфейсы не могут содержать полей"):
5. Абстрактный класс может иметь все модификаторы доступа для всех своих объявлений членов, в то время как в интерфейсе мы не можем объявлять никаких модификаторов доступа для членов (включая
Самые часто задаваемые вопросы на собеседовании по C#
4. Чем отличается интерфейс от абстрактного класса в C#?
Это, вероятно, самый часто задаваемый вопрос в мире .Net. Теоретически между абстрактным классом и интерфейсом есть 5 отличий, которые перечислены ниже:
1. Класс может реализовывать любое количество интерфейсов, но дочерний класс может наследовать только от одного абстрактного класса.
2. Абстрактный класс может иметь неабстрактные (конкретные) методы, в то время как в случае интерфейса все методы должны быть абстрактными. (Начиная с C# 8 допускается реализация по умолчанию интерфейсных методов).
3. Абстрактный класс может объявлять или использовать любые переменные, в то время как интерфейсу это запрещено. То есть следующий код приведёт к ошибке компиляции "Interfaces cannot contain fields" ("Интерфейсы не могут содержать полей"):
interface TestInterface4. Абстрактный класс может иметь объявление конструктора, а интерфейс нет. Возникает аналогичная пункту 3 ошибка компиляции "Interfaces cannot contain constructors" ("Интерфейсы не могут содержать конструкторов")
{
int x = 4; // Неверное объявление в интерфейсе
void getMethod();
string getName();
}
abstract class TestAbstractClass
{
int i = 4;
int k = 3;
public abstract void getClassName();
}
5. Абстрактный класс может иметь все модификаторы доступа для всех своих объявлений членов, в то время как в интерфейсе мы не можем объявлять никаких модификаторов доступа для членов (включая
public
), так как все члены интерфейса неявно открытые. Следующий код приведёт к ошибке компиляции "The modifier 'public' is not valid for this item" ("Модификатор 'public' недопустим для этого элемента"):interface TestInterfaceИсточник: https://www.c-sharpcorner.com
{
public void getMethod();
public string getName();
}
День сто четырнадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
5. В чём разница между операторами "continue" и "break" в C#?
Используя оператор
Пример
Самые часто задаваемые вопросы на собеседовании по C#
5. В чём разница между операторами "continue" и "break" в C#?
Используя оператор
break
, вы можете «выпрыгнуть из цикла», тогда как, используя оператор continue
, вы можете «перепрыгнуть через одну итерацию» и продолжить выполнение цикла.Пример
break
:for (int i = 0; i <= 5; i++) {Вывод:
if (i == 4) {
break;
}
Console.WriteLine(i);
Console.ReadLine();
}
0Пример
1
2
3
continue
:for (int i = 0; i <= 5; i++) {Вывод:
if (i == 4) {
continue;
}
Console.WriteLine(i);
Console.ReadLine();
}
1Источник: https://www.c-sharpcorner.com
2
3
5
День сто пятнадцатый. #ЗаметкиНаПолях
Случайные числа в C#
Вокруг генерации случайных чисел всегда ходит много мифов и поэтому возникает много путаницы. Можно ли использовать простую конструкцию:
На самом деле в подавляющем большинстве случаев для генерации случайных (псевдослучайных) чисел достаточно следующего кода:
1. Указание числа посева (seed) в конструкторе класса
Для случайного перемешивания небольших коллекций вполне подойдёт простой код LINQ:
Источники:
- https://www.youtube.com/watch?v=kW84q8WOBdU
- https://stackoverflow.com/questions/273313/randomize-a-listt/
Случайные числа в C#
Вокруг генерации случайных чисел всегда ходит много мифов и поэтому возникает много путаницы. Можно ли использовать простую конструкцию:
var random = new Random();или же необходимо подключать криптографические библиотеки?
На самом деле в подавляющем большинстве случаев для генерации случайных (псевдослучайных) чисел достаточно следующего кода:
Random random = new Random();Однако есть несколько ограничений:
Console.WriteLine(random.Next());
1. Указание числа посева (seed) в конструкторе класса
Random
приведёт к созданию одинаковых последовательностей случайных чисел, поэтому используйте конструктор без параметров. Например, следующий код будет генерировать одну и ту же последовательность при каждом запуске:Random random = new Random(10010);2. Создавайте объект
for (int i = 0; i < 10; i++)
{
Console.WriteLine(random.Next());
}
Random
только один раз. Если метод должен использовать случайное число, не создавайте новый объект Random
внутри метода. Создайте его вне метода и передавайте в метод в качестве параметра:Random random = new Random();вместо
SomeMethod(random);
SomeMethod(new Random());Это связано с пунктом 1. Конструктор класса Random без параметров берёт в качестве числа посева системное время в формате тактов процессора (1 такт = 100 наносекунд). Однако по природе своей реализации системные часы не различают разницу во времени примерно в 15 миллисекунд. Поэтому последовательные вызовы конструктора класса
Random
могут привести к созданию нескольких одинаковых случайных последовательностей.Для случайного перемешивания небольших коллекций вполне подойдёт простой код LINQ:
var shuffeledList = somelist.OrderBy(x => random.Next());Для больших коллекций есть более эффективные алгоритмы, например, Фишера-Йетса (здесь используем метод-расширение для
IList
):private static Random rng = new Random();Использование:
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
List<Product> products = GetProducts();Для небольшого количества случаев, когда требуется криптографически безопасное случайное число (например, при создании случайного пароля), используйте класс
products.Shuffle();
RNGCryptoServiceProvider
или наследуйте от System.Security.Cryptography.RandomNumberGenerator
.Источники:
- https://www.youtube.com/watch?v=kW84q8WOBdU
- https://stackoverflow.com/questions/273313/randomize-a-listt/
День сто шестнадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
6. В чем разница между константой и полем только для чтения в C#?
Поле
Поле
Например, у нас есть тестовый класс, в котором у нас две переменные: одна только для чтения, а другая - константа.
Если мы создадим экземпляр класса
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по C#
6. В чем разница между константой и полем только для чтения в C#?
Поле
сonst
- это константа, переменная, значение которой является постоянным со времени компиляции. Присваивать значение константе обязательно. По умолчанию поле const является статическим, и мы не можем изменить значение переменной const при выполнении программы.Поле
readonly
- это поле, значение которого мы можем изменить или назначить во время выполнения, но только через нестатический конструктор.Например, у нас есть тестовый класс, в котором у нас две переменные: одна только для чтения, а другая - константа.
class Test {При попытке изменить значение константы в конструкторе возникает исключение "
readonly int readOnly = 10;
const int cons = 10;
public Test() {
read = 100;
//cons = 100;
}
public void Check() {
Console.WriteLine("Read only: {0}", readOnly);
Console.WriteLine("Const: {0}", cons);
}
}
The left-hand side of an assignment must be a variable, property or indexer
" ("Левая часть оператора присваивания должна быть переменной, свойством или индексатором
").Если мы создадим экземпляр класса
Test
и вызовем метод Check()
, мы получим следующий вывод:Read only: 100При компиляции значения const записываются непосредственно вместо вызывающего константу кода. В предыдущем примере все обращения к cons при компиляции будут заменены на 10. Это может иметь как преимущества, так и недостатки. Код работает гораздо быстрее, так как избегает лишнего вызова, но. Если вам нужно изменить значение константы, вам нужно перекомпилировать все сборки, обращающиеся к ней. Поэтому в общем случае, если к константе обращаются другие сборки, предпочтительнее использовать поле
Const: 10
readonly
. Также константа бесполезна, если значение выбирается во время выполнения, например, из файла конфигурации.Источник: https://www.c-sharpcorner.com
C-Sharpcorner
C# Corner: AI-Powered Upskilling and Growth Platform
C# Corner is a global community focused on members education and growth through tutorials, videos, podcasts, conferences, hackathons, certifications, speaking opportunities, and mentorship programs.
День сто семнадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
7. В чем разница между ключевыми словами ref и out?
Ключевые слова
Ref
Ключевое слово
Ключевое слово out возвращает аргумент из метода по ссылке. Оно очень похоже на ключевое слово
Ref
1. Параметр или аргумент должен быть инициализирован, прежде чем он передаётся в
2. Не требуется присваивать или инициализировать значение параметра (переданного с помощью
3. Передача значения параметра с помощью
4. При использовании
Out
1. Не обязательно инициализировать параметр или аргумент перед его передачей в
2. Вызываемый метод обязан присвоить или инициализировать значение параметра (переданного с помощью
3. Передача значения параметра с помощью
4. При использовании
Сходства
1. И
2. Свойства не являются переменными, поэтому их нельзя передавать как параметр
Перегрузка методов
Допустима перегрузка методов, если один метод принимает параметры по значению, а другой по ссылке с помощью
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по C#
7. В чем разница между ключевыми словами ref и out?
Ключевые слова
ref
и out
используются для передачи аргументов в метод или функцию. Оба указывают, что аргумент/параметр передается по ссылке. По умолчанию параметры передаются в метод по значению. Ref
Ключевое слово
ref
передает аргументы по ссылке. Это означает, что любые изменения, внесенные в этот аргумент в методе, будут отражены в этой переменной, когда управление вернется в вызывающий метод:public static string GetNextName(ref int id)Вывод:
{
string returnText = "Next-" + id;
id += 1;
return returnText;
}
static void Main(string[] args)
{
int i = 1;
Console.WriteLine("Previous value of i:" + i);
string test = GetNextName(ref i);
Console.WriteLine(test);
Console.WriteLine("Current value of i:" + i);
Console.ReadLine();
}
Previous value of i:1Out
Next-1
Current value of i:2
Ключевое слово out возвращает аргумент из метода по ссылке. Оно очень похоже на ключевое слово
ref
.public static string GetNextName(out int id)Вывод:
{
id = 1;
string returnText = "Next-" + id;
return returnText;
}
static void Main(string[] args)
{
int i;
string test = GetNextName(out i);
Console.WriteLine(test);
Console.WriteLine("Current value of i:" + i);
Console.ReadLine();
}
Next-1Отличия
Current value of i:1
Ref
1. Параметр или аргумент должен быть инициализирован, прежде чем он передаётся в
ref
.2. Не требуется присваивать или инициализировать значение параметра (переданного с помощью
ref
) внутри вызываемого метода перед возвратом в вызывающий метод.3. Передача значения параметра с помощью
ref
полезна, когда вызываемый метод также необходим для изменения переданного параметра.4. При использовании
ref
, данные могут передаваться в двух направлениях.Out
1. Не обязательно инициализировать параметр или аргумент перед его передачей в
out
.2. Вызываемый метод обязан присвоить или инициализировать значение параметра (переданного с помощью
out
) перед возвратом в вызывающий метод.3. Передача значения параметра с помощью
out
полезна, когда из функции или метода необходимо вернуть несколько значений.4. При использовании
out
, данные передаются только однонаправленно (от вызываемого метода к вызывающему).Сходства
1. И
ref
, и out
ведут себя по-разному во время выполнения, но они трактуются одинаково при компиляции.2. Свойства не являются переменными, поэтому их нельзя передавать как параметр
out
или ref
.Перегрузка методов
Допустима перегрузка методов, если один метод принимает параметры по значению, а другой по ссылке с помощью
ref
или out
. Однако, поскольку и ref
, и out
трактуются одинаково при компиляции, методы не могут быть перегружены, если один метод принимает аргумент как ref
, а другой - как out
.public static string GetNextName(ref int id)При компиляции этого кода будет выброшено исключение: "
{
string returnText = "Next-" + id.ToString();
id += 1;
return returnText;
}
public static string GetNextName(out int id)
{
id = 1;
string returnText = "Next-" + id.ToString();
return returnText;
}
Сannot define an overloaded method that differs only on parameter modifiers 'out' and 'ref'
" ("Нельзя определить перегруженные методы, которые отличаются только модификаторами 'out' и 'ref'
").Источник: https://www.c-sharpcorner.com
👍2
День сто восемнадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
8. Можно ли использовать 'this' в статическом методе?
Ключевое слово '
Мы не можем использовать '
Самые часто задаваемые вопросы на собеседовании по C#
8. Можно ли использовать 'this' в статическом методе?
Ключевое слово '
this
' в C# является специальным типом ссылочной переменной, которая неявно определяется в каждом конструкторе и нестатическом методе как первый параметр типа класса, в котором она определена.Мы не можем использовать '
this
' в статическом методе, потому что ключевое слово 'this
' возвращает ссылку на текущий экземпляр класса, который его содержит. Статические методы (или любые статические члены) не принадлежат конкретному экземпляру. Они существуют без создания экземпляра класса и вызываются с именем класса не по экземпляру, поэтому мы не можем использовать это ключевое слово в теле статических методов, но в случае с методами расширения мы можем использовать его как модификатор параметра метода. Следующий код определяет метод расширения для типа string
, который возвращает либо подстроку, либо всю исходную строку, если length больше длины строки (вместо ArgumentOutOfRangeException
):public static string Substr(this string s, int length)Источник: https://www.c-sharpcorner.com
{
if (s.Length >= length)
return s.Substring(0, length);
return s;
}
👍1
День сто девятнадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
9. В чем разница между методами dispose и finalize в C#?
Мы использовали метод
Dispose
Сборщик мусора (GC) играет важную роль в управлении памятью в .NET, поэтому программист может сосредоточиться на функциональности приложения. Сборщик мусора отвечает за освобождение памяти (объектов), которая не используется приложением. Но у него есть ограничение: он может восстанавливать или освобождать только память, которая используется управляемыми ресурсами. Есть несколько ресурсов, которые GC не может высвободить, поскольку у них нет информации о том, как запросить память. Это такие ресурсы, как обработчики файлов, обработчики окон, сетевые сокеты, соединения с базой данных и т.д. Если ваше приложение использует эти ресурсы, то в его ответственности освобождать неуправляемые ресурсы. Например, если мы откроем файл в нашей программе и не закроем его после обработки, этот файл не будет доступен для других операций или использования другим приложением, т.к. они не смогут открыть или изменить этот файл. Для этого класс
Close или Dispose
Некоторые объекты предоставляют оба метода: и
Тогда зачем нам метод
Создание метода Dispose
Чтобы реализовать освобождение ресурса через метод
Самые часто задаваемые вопросы на собеседовании по C#
9. В чем разница между методами dispose и finalize в C#?
Мы использовали метод
Dispose
для удаления объектов в .NET. Для этой же цели мы также можем использовать метод Finalize
. В чём же разница между ними?Dispose
Сборщик мусора (GC) играет важную роль в управлении памятью в .NET, поэтому программист может сосредоточиться на функциональности приложения. Сборщик мусора отвечает за освобождение памяти (объектов), которая не используется приложением. Но у него есть ограничение: он может восстанавливать или освобождать только память, которая используется управляемыми ресурсами. Есть несколько ресурсов, которые GC не может высвободить, поскольку у них нет информации о том, как запросить память. Это такие ресурсы, как обработчики файлов, обработчики окон, сетевые сокеты, соединения с базой данных и т.д. Если ваше приложение использует эти ресурсы, то в его ответственности освобождать неуправляемые ресурсы. Например, если мы откроем файл в нашей программе и не закроем его после обработки, этот файл не будет доступен для других операций или использования другим приложением, т.к. они не смогут открыть или изменить этот файл. Для этого класс
FileStream
предоставляет метод Dispose
. Мы должны вызвать этот метод после завершения обработки файла. В противном случае будет выброшено исключение "Access Denied or file is being used by other program
" ("Доступ запрещен или файл используется другой программой
").Close или Dispose
Некоторые объекты предоставляют оба метода: и
Close
, и Dispose
. Для потоковых классов (наследников Stream
) оба служат одной цели. Метод Dispose
вызывает метод Close
внутри себя.Тогда зачем нам метод
Dispose
в классе Stream
? Наличие метода Dispose
позволит вам написать приведенный ниже код и неявно вызвать метод Dispose
, который, в конечном итоге, вызовет метод Close
.using(FileStream file = new FileStream("path", FileMode.Open, FileAccess.Read))Но в некоторых классах эти методы ведут себя немного по-разному. Например, класс
{
//Выполняем операции с файлом
}
Connection
. Если вызывается метод Close
, он отключается от базы данных и освобождает все ресурсы, используемые объектом подключения, а метод Open
снова подключает его к базе данных без повторной инициализации объекта подключения. А метод Dispose
полностью освобождает объект подключения, и его нельзя открыть, просто вызвав метод Open
. Нам придется повторно инициализировать объект Connection
.Создание метода Dispose
Чтобы реализовать освобождение ресурса через метод
Dispose
для вашего пользовательского класса, вам нужно реализовать интерфейс IDisposable
. Интерфейс IDisposable
предоставляет метод Dispose
, в котором будет написан код для освобождения неуправляемого ресурса.Finalize
Метод
Возникает вопрос, когда реализовать финализатор? Это может быть любой неуправляемый ресурс, например файловый поток, объявленный на уровне класса. Возможно, мы не знаем, на какой стадии или на каком шаге программы следует закрыть файл. Этот объект используется во многих местах приложения. Так что в этом сценарии метод
Финализация немного дороже в использовании. Она не очищает память сразу. Когда приложение запускается, сборщик мусора поддерживает отдельную очередь на финализацию, куда он добавляет все объекты, которые должны быть финализированы. Другими словами, сборщик мусора знает, для какого объекта реализован метод
Заключение
Рекомендуется не применять метод
Источник: https://www.c-sharpcorner.com
Метод
Finalize
также называется деструктором класса. Его нельзя явно вызвать в коде. Только сборщик мусора может вызывать метод Finalize
(финализатор), когда объект становится недоступным. Финализатор не может быть реализован напрямую, только через объявление деструктора. Следующий класс иллюстрирует, как объявить деструктор. Рекомендуется реализовывать методы Finalize
и Dispose
вместе, если вам нужно реализовать деструктор. После компиляции деструктор становится методом Finalize
.public class MyClass: IDisposable {Использование Finalize
//Конструктор
public MyClass() {
//Инициализация
}
//Деструктор или финализатор
~MyClass() {
this.Dispose();
}
public void Dispose() {
//код для освобождения неуправляемых ресурсов
}
}
Возникает вопрос, когда реализовать финализатор? Это может быть любой неуправляемый ресурс, например файловый поток, объявленный на уровне класса. Возможно, мы не знаем, на какой стадии или на каком шаге программы следует закрыть файл. Этот объект используется во многих местах приложения. Так что в этом сценарии метод
Finalize
- подходящее место, где может быть освобожден неуправляемый ресурс. Это означает, что память, полученная неуправляемым ресурсом, очищается, как только объект станет недоступен для приложения.Финализация немного дороже в использовании. Она не очищает память сразу. Когда приложение запускается, сборщик мусора поддерживает отдельную очередь на финализацию, куда он добавляет все объекты, которые должны быть финализированы. Другими словами, сборщик мусора знает, для какого объекта реализован метод
Finalize
. Когда объект становится недоступным и готов к очистке, сборщик мусора вызывает метод Finalize
этого объекта и удаляет его из очереди на финализацию. На этой итерации сбора мусора сборщик просто очищает память, которая используется неуправляемым ресурсом. Память, используемая управляемым ресурсом (самим объектом), все еще находится в куче в качестве недоступной ссылки. Эта память освобождается, когда сборщик мусора запустится в следующий раз. Из-за метода финализации сборщик не очищает всю память, связанную с объектом, с первой попытки.Заключение
Рекомендуется не применять метод
Finalize
без крайней необходимости. В приоритете всегда должна быть реализация метода Dispose
и очистка неуправляемой памяти, как только программа закончит работу с ней.Источник: https://www.c-sharpcorner.com
День сто двадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
10. В чём разница между String и StringBuilder в C#?
Класс
Хотя строка является ссылочным типом, операторы равенства (
С другой стороны,
Компилятор создает новый строковый объект для каждой конкатенации строк для хранения новой последовательности символов (другими словами, существующей строки и новых данных), и этот новый объект возвращается обратно в переменную.
Например, если вы объединяете две строки, то конкатенация строк выделяет новую строку длины (
Это приводит к многократному повторному копированию строк, например объединение N строк (
С другой стороны, объект
Например, если вы объединяете 20 строк,
Когда что использовать
Не используйте строку, если вы не знаете количество конкатенаций или если количество конкатенаций большое:
1.
2. Также, если у вас есть массив, который вы хотите объединить в строку, рассмотрите возможность явного вызова "
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по C#
10. В чём разница между String и StringBuilder в C#?
Класс
String
из пространства имён System
– это последовательная коллекция символов Unicode (объектов System.Char
), представляющая собой текст. Объект String
является неизменяемым. Максимальный размер объекта String
в памяти составляет 2 ГБ (около 1 миллиарда символов).Хотя строка является ссылочным типом, операторы равенства (
==
и !=
) Определены для сравнения значений строковых объектов, а не ссылок. Однако после упаковки сравнение происходит на строковых экземплярах:string a = "hello";Последняя строка выдаёт
string b = "h";
b += "ello"; // Добавляем к строке 'b'
Console.WriteLine(a==b); // true
Console.WriteLine((object)a == (object)b); // false
false
, поскольку после упаковки объектов сравниваются ссылки на экземпляры.С другой стороны,
StringBuilder
(System.Text
) представляет собой изменяемую строку символов. Этот класс не может быть унаследован. Емкость этого объекта по умолчанию составляет 16 символов, а максимальная емкость превышает 2 миллиарда символов.StringBuilder sb = new StringBuilder();Как это работает
sb.Append("Hello");
sb.Append("World");
Console.WriteLine(sb.ToString());
Компилятор создает новый строковый объект для каждой конкатенации строк для хранения новой последовательности символов (другими словами, существующей строки и новых данных), и этот новый объект возвращается обратно в переменную.
Например, если вы объединяете две строки, то конкатенация строк выделяет новую строку длины (
str1.Length + str2.Length
) и копирует первую и вторую строки в эту строку.Это приводит к многократному повторному копированию строк, например объединение N строк (
var result = str1 + str2 + str3 + ... + strN;
) потребует N-1 выделения памяти и N-1 операций копирования. Это может стать очень дорогим для больших значений N.С другой стороны, объект
StringBuilder
поддерживает буфер для размещения конкатенации новых данных. Новые данные добавляются в буфер, если доступно пространство; в противном случае выделяется новый больший буфер, данные из исходного буфера копируются в новый буфер, а новые данные добавляются в новый буфер.Например, если вы объединяете 20 строк,
StringBuilder
просто добавляет одну за другой в свой буфер, а затем возвращает результат по запросу.Когда что использовать
Не используйте строку, если вы не знаете количество конкатенаций или если количество конкатенаций большое:
string x = "";Используйте класс
for (int i = 0; i < 100000; i++)
{
x += "!";
}
String
, если вы объединяете фиксированное число объектов String
. В этом случае компилятор может даже объединить отдельные операции конкатенации в одну операцию, особенно в случае конкатенации строковых литералов:string x = "Hello" + " " + "World";С другой стороны, не используйте
StringBuilder
для тривиальной конкатенации, поскольку выделение и инициализация StringBuilder
занимает некоторое время, которое может оказаться бесполезным для небольшого числа конкатенаций:StringBuilder sb = new StringBuilder();Прочие Советы
sb.Append("Hello");
sb.Append("World");
Console.WriteLine(sb.ToString());
1.
StringBuilder
может быть еще более эффективным при указании размера буфера в конструкторе, чтобы избежать излишних удвоений размера буфера, когда ему не хватает места.2. Также, если у вас есть массив, который вы хотите объединить в строку, рассмотрите возможность явного вызова "
String.Concat
" или "String.Join
", если вам нужен разделитель.Источник: https://www.c-sharpcorner.com
День сто двадцать второй. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
11. Что такое закрытый класс в C#?
Закрытые классы используются для ограничения наследования в объектно-ориентированном программировании. Класс, определёный как закрытый, не может быть унаследован.
В C# для определения закрытого класса используется модификатор
Все структуры закрыты. Вы не можете унаследовать класс из структуры.
Закрытые методы и свойства
Вы также можете использовать модификатор
Основная цель закрытого класса состоит в том, чтобы запретить наследование от класса. Один из лучших вариантов использования закрытых классов - это класс со статическими членами. Например, классы
Если класс не предназначен для наследования, подклассы могут нарушать инварианты класса. Поэтому, как правило, рекомендуется закрывать любой класс, явно не предназначенный для наследования от него.
В библиотеке классов Microsoft наследование ограничено только теми местами, где оно действительно имеет смысл. Очень многие классы, например
Источники:
- https://www.c-sharpcorner.com
- https://stackoverflow.com/questions/7777611/when-and-why-would-you-seal-a-class
Самые часто задаваемые вопросы на собеседовании по C#
11. Что такое закрытый класс в C#?
Закрытые классы используются для ограничения наследования в объектно-ориентированном программировании. Класс, определёный как закрытый, не может быть унаследован.
В C# для определения закрытого класса используется модификатор
sealed
. Если создать класс производный от закрытого класса, то компилятор выдаст ошибку.Все структуры закрыты. Вы не можете унаследовать класс из структуры.
Закрытые методы и свойства
Вы также можете использовать модификатор
sealed
для метода или свойства, которое переопределяет виртуальный метод или свойство базового класса. Это позволяет вам разрешать классам наследовать от вашего класса, но не позволяет другим разработчикам, использующим ваши классы, переопределять определенные виртуальные методы и свойства.class XЗачем использовать закрытые классы?
{
protected virtual void F()
{
Console.WriteLine("X.F");
}
protected virtual void F2()
{
Console.WriteLine("X.F2");
}
}
class Y : X
{
sealed protected override void F()
{
Console.WriteLine("Y.F");
}
protected override void F2()
{
Console.WriteLine("Y.F2");
}
}
class Z : Y
{
// Попытка переопределить F приводит к ошибке компиляции CS0239.
protected override void F()
{
Console.WriteLine("C.F");
}
// Допустимо переопределить F2
protected override void F2()
{
Console.WriteLine("Z.F2");
}
}
Основная цель закрытого класса состоит в том, чтобы запретить наследование от класса. Один из лучших вариантов использования закрытых классов - это класс со статическими членами. Например, классы
Pens
и Brushes
в пространстве имен System.Drawing
. Класс Pens
представляет ручки со стандартными цветами. Этот класс имеет только статические члены. Например, Pens.Blue
представляет собой ручку синего цвета. Аналогично, класс Brushes
представляет стандартные кисти. Brushes.Red
представляет собой кисть с красным цветом.Если класс не предназначен для наследования, подклассы могут нарушать инварианты класса. Поэтому, как правило, рекомендуется закрывать любой класс, явно не предназначенный для наследования от него.
В библиотеке классов Microsoft наследование ограничено только теми местами, где оно действительно имеет смысл. Очень многие классы, например
String
, закрыты. Ключевое слово sealed
сообщает CLR, что ниже по иерархии нет классов для поиска методов, что повышает производительность.Источники:
- https://www.c-sharpcorner.com
- https://stackoverflow.com/questions/7777611/when-and-why-would-you-seal-a-class
👍2
День сто двадцать третий. #юмор
"C# 7.0 в кратце" и "C# подробно". Похоже, одна из книг меня обманывает.
"C# 7.0 в кратце" и "C# подробно". Похоже, одна из книг меня обманывает.
День сто двадцать четвёртый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
12. Что такое частичный класс в C#?
Частичный класс разделяет определение класса на два или более исходных (.cs) файлов. Вы можете создать определение класса в нескольких физических файлах, но при компиляции классов оно будет скомпилировано как один класс.
Преимущества
1. Вы можете разделить код разработки пользовательского интерфейса и код бизнес-логики, чтобы его было легко читать и понимать. Например, вы разрабатываете веб-приложение с использованием Visual Studio и добавляете новую веб-форму, тогда есть два исходных файла: «aspx.cs» и «aspx.designer.cs». Эти два файла имеют один и тот же класс с частичным ключевым словом. Класс ".aspx.cs" имеет код бизнес-логики, а "aspx.designer.cs" - определение элемента управления пользовательского интерфейса.
2. При работе с автоматически сгенерированным исходным кодом код можно добавить в класс, не создавая заново исходный файл. Например, вы работаете с LINQ to SQL и создаете файл DBML. Теперь, когда вы перетаскиваете таблицу, она создает частичный класс в designer.cs, и все столбцы таблицы имеют свойства в этом классе. Допустим, вам нужно добавить столбцы к этой таблице без добавления столбцов в таблицу базы данных. Вы можете создать отдельный файл для этого класса, который имеет свойства для этих столбцов, и будет частичным классом. То есть вы можете написать свой код, не вмешиваясь в код, сгенерированный системой.
3. Несколько разработчиков могут одновременно работать с кодом одного и того же класса.
4. Вы можете лучше поддерживать свое приложение, сжимая большие классы. Предположим, у вас есть класс с несколькими интерфейсами, поэтому вы можете создавать несколько исходных файлов для реализации каждого интерфейса. Легко понять и поддерживать реализацию интерфейса, в отдельном файле частичного класса.
1. Вам нужно использовать ключевое слово partial в каждой части частичного класса.
2. Имя каждой части частичного класса должно быть одинаковым, но имена файлов для каждой части частичного класса могут быть разными.
3. Все части частичного класса должны находиться в одном пространстве имен.
4. Каждая часть частичного класса должна находиться в одной сборке или DLL, другими словами, вы не можете создать частичный класс в исходных файлах другого проекта библиотеки классов.
5. Каждая часть частичного класса должна иметь одинаковый уровень доступа.
6. Если вы наследуете класс или интерфейс в частичном классе, то он наследуется во всех частях частичного класса.
7. Если часть частичного класса закрыта от наследования, тогда весь класс будет закрыт.
8. Если часть частичного класса является абстрактной, тогда весь класс будет абстрактным.
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по C#
12. Что такое частичный класс в C#?
Частичный класс разделяет определение класса на два или более исходных (.cs) файлов. Вы можете создать определение класса в нескольких физических файлах, но при компиляции классов оно будет скомпилировано как один класс.
Преимущества
1. Вы можете разделить код разработки пользовательского интерфейса и код бизнес-логики, чтобы его было легко читать и понимать. Например, вы разрабатываете веб-приложение с использованием Visual Studio и добавляете новую веб-форму, тогда есть два исходных файла: «aspx.cs» и «aspx.designer.cs». Эти два файла имеют один и тот же класс с частичным ключевым словом. Класс ".aspx.cs" имеет код бизнес-логики, а "aspx.designer.cs" - определение элемента управления пользовательского интерфейса.
2. При работе с автоматически сгенерированным исходным кодом код можно добавить в класс, не создавая заново исходный файл. Например, вы работаете с LINQ to SQL и создаете файл DBML. Теперь, когда вы перетаскиваете таблицу, она создает частичный класс в designer.cs, и все столбцы таблицы имеют свойства в этом классе. Допустим, вам нужно добавить столбцы к этой таблице без добавления столбцов в таблицу базы данных. Вы можете создать отдельный файл для этого класса, который имеет свойства для этих столбцов, и будет частичным классом. То есть вы можете написать свой код, не вмешиваясь в код, сгенерированный системой.
3. Несколько разработчиков могут одновременно работать с кодом одного и того же класса.
4. Вы можете лучше поддерживать свое приложение, сжимая большие классы. Предположим, у вас есть класс с несколькими интерфейсами, поэтому вы можете создавать несколько исходных файлов для реализации каждого интерфейса. Легко понять и поддерживать реализацию интерфейса, в отдельном файле частичного класса.
public interface IRegisterНекоторые моменты, на которые стоит обратить внимание:
{
//Функционал регистрации
}
public interface ILogin
{
//Функционал входа в систему
}
//Файл UserRegister.cs
public partial class User : IRegister, ILogin
{
//реализация IRegister
}
//Файл UserLogin.cs
public partial class User
{
//реализация ILogin
}
1. Вам нужно использовать ключевое слово partial в каждой части частичного класса.
2. Имя каждой части частичного класса должно быть одинаковым, но имена файлов для каждой части частичного класса могут быть разными.
3. Все части частичного класса должны находиться в одном пространстве имен.
4. Каждая часть частичного класса должна находиться в одной сборке или DLL, другими словами, вы не можете создать частичный класс в исходных файлах другого проекта библиотеки классов.
5. Каждая часть частичного класса должна иметь одинаковый уровень доступа.
6. Если вы наследуете класс или интерфейс в частичном классе, то он наследуется во всех частях частичного класса.
7. Если часть частичного класса закрыта от наследования, тогда весь класс будет закрыт.
8. Если часть частичного класса является абстрактной, тогда весь класс будет абстрактным.
Источник: https://www.c-sharpcorner.com
День сто двадцать шестой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по 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