.NET Разработчик
6.51K subscribers
427 photos
2 videos
14 files
2.04K links
Дневник сертифицированного .NET разработчика.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День сто семнадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по 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:1
Next-1
Current value of i:2

Out
Ключевое слово 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' в статическом методе?
Ключевое слово 'this' в C# является специальным типом ссылочной переменной, которая неявно определяется в каждом конструкторе и нестатическом методе как первый параметр типа класса, в котором она определена.
Мы не можем использовать 'this' в статическом методе, потому что ключевое слово 'this' возвращает ссылку на текущий экземпляр класса, который его содержит. Статические методы (или любые статические члены) не принадлежат конкретному экземпляру. Они существуют без создания экземпляра класса и вызываются с именем класса не по экземпляру, поэтому мы не можем использовать это ключевое слово в теле статических методов, но в случае с методами расширения мы можем использовать его как модификатор параметра метода. Следующий код определяет метод расширения для типа string, который возвращает либо подстроку, либо всю исходную строку, если length больше длины строки (вместо ArgumentOutOfRangeException):
public static string Substr(this string s, int length)
{
if (s.Length >= length)
return s.Substring(0, length);
return s;
}

Источник: https://www.c-sharpcorner.com
👍1
День сто девятнадцатый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по 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
Метод Finalize также называется деструктором класса. Его нельзя явно вызвать в коде. Только сборщик мусора может вызывать метод Finalize (финализатор), когда объект становится недоступным. Финализатор не может быть реализован напрямую, только через объявление деструктора. Следующий класс иллюстрирует, как объявить деструктор. Рекомендуется реализовывать методы Finalize и Dispose вместе, если вам нужно реализовать деструктор. После компиляции деструктор становится методом Finalize.
public class MyClass: IDisposable {
//Конструктор
public MyClass() {
//Инициализация
}
//Деструктор или финализатор
~MyClass() {
this.Dispose();
}
public void Dispose() {
//код для освобождения неуправляемых ресурсов
}
}
Использование Finalize
Возникает вопрос, когда реализовать финализатор? Это может быть любой неуправляемый ресурс, например файловый поток, объявленный на уровне класса. Возможно, мы не знаем, на какой стадии или на каком шаге программы следует закрыть файл. Этот объект используется во многих местах приложения. Так что в этом сценарии метод Finalize - подходящее место, где может быть освобожден неуправляемый ресурс. Это означает, что память, полученная неуправляемым ресурсом, очищается, как только объект станет недоступен для приложения.
Финализация немного дороже в использовании. Она не очищает память сразу. Когда приложение запускается, сборщик мусора поддерживает отдельную очередь на финализацию, куда он добавляет все объекты, которые должны быть финализированы. Другими словами, сборщик мусора знает, для какого объекта реализован метод Finalize. Когда объект становится недоступным и готов к очистке, сборщик мусора вызывает метод Finalize этого объекта и удаляет его из очереди на финализацию. На этой итерации сбора мусора сборщик просто очищает память, которая используется неуправляемым ресурсом. Память, используемая управляемым ресурсом (самим объектом), все еще находится в куче в качестве недоступной ссылки. Эта память освобождается, когда сборщик мусора запустится в следующий раз. Из-за метода финализации сборщик не очищает всю память, связанную с объектом, с первой попытки.

Заключение
Рекомендуется не применять метод Finalize без крайней необходимости. В приоритете всегда должна быть реализация метода Dispose и очистка неуправляемой памяти, как только программа закончит работу с ней.

Источник: 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# для определения закрытого класса используется модификатор 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#
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# проверяет количество передаваемых параметров и типы параметров и принимает решение, какой метод вызывать, либо выдаёт ошибку времени компиляции, если подходящий метод не найден:
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
Class B
ConsoleApp1.C

Источник: https://www.c-sharpcorner.com
👍1
День сто двадцать седьмой. #TipsAndTricks
27. Точка прерывания на автоматически реализованном свойстве
Если в вашей компании по финансовым, юридическим, религиозным или каким-то иным причинам используют старую версию Visual Studio, то вам порой приходится сталкиваться с проблемами, давно решёнными в более современных версиях.
Проблема (в VS версии 2013)
C# поддерживает автоматически реализованные свойства. Во время отладки иногда полезно устанавливать точки останова при обращении к свойству, особенно когда оно вызывается из нескольких мест, и утомительно находить их все и ставить множество точек останова. Итак, рассмотрим следующий пример:
namespace MyName {
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
}
}
}
Если вы попытаетесь установить точку останова на строках 4 или 5, то, к сожалению, точка останова переместится в ближайшее подходящее место, а не останется на этой строке.

Решение для 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?
При работе с базой данных иногда можно запутаться. Могут возникнуть некоторые вопросы, например, что использовать для извлечения данных из БД, IEnumerable или IQueryable?
Если коротко:
- IEnumerable - выполняет запрос SELECT на стороне сервера, загружает все данные в память на стороне клиента, а затем выполняет фильтрацию.
- IQueryable - выполняет запрос SELECT на стороне сервера со всеми фильтрами.
Разница в том, что IQueryable<T> - это интерфейс, который позволяет работать LINQ-to-SQL (на самом деле, LINQ-to-чтоугодно). Поэтому, если вы дополнительно уточните свой запрос в IQueryable<T>, этот запрос будет выполнен в базе данных, если это возможно.
В случае IEnumerable<T> это будет LINQ-to-object, то есть все объекты, соответствующие исходному запросу, должны быть загружены в память из базы данных:
IQueryable<Customer> custs = ...;
// Затем...
var goldCustomers = custs.Where(c => c.IsGold);
Этот код выполнит SQL-запрос для выбора только золотых клиентов. А вот следующий код выполнит исходный запрос к базе данных, а затем отфильтрует не-золотых клиентов в памяти:
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#
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. 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#?
Виртуальный метод - это метод, который можно переопределить в производных классах. Виртуальный метод имеет реализацию в базовом классе. Он используется, когда базовая функциональность метода одинакова, но иногда требуется больше функциональности в производном классе. В базовом классе создается виртуальный метод, используя ключевое слово virtual, который можно переопределить в производном классе с помощью ключевого слова override.
- Производному классу необязательно переопределять этот метод.
- Когда вызывается виртуальный метод, тип объекта во время выполнения проверяется для переопределяющего члена. Вызывается переопределяющий член в наиболее производном классе. То есть может быть вызван и исходный член, если ни один производный класс не переопределил его.
- По умолчанию методы не виртуальные. Нельзя переопределить не виртуальный метод.
- Нельзя использовать виртуальный модификатор с модификаторами static, abstract, private или override.

Источники: https://www.c-sharpcorner.com
День сто тридцать четвёртый. #ЗаметкиНаПолях
Анонимные методы
Создание анонимных методов – это способ передать блок кода в качестве параметра делегата:
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#?
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