День сто тридцать девятый. #ЗаметкиНаПолях
Лямбда-выражения. Окончание
Вывод типа в лямбда-выражениях
При написании лямбда-выражений часто нет необходимости указывать тип для входных параметров, поскольку компилятор может вывести тип на основе тела лямбда выражения, типов параметров и других факторов, описанных в спецификации языка C#. Для большинства стандартных операторов запросов первым вводом является тип элементов в исходной последовательности. Если вы запрашиваете
- Лямбда должна содержать то же количество параметров, что и тип делегата.
- Каждый входной параметр в лямбда-выражении должен быть неявно преобразован в соответствующий ему параметр делегата.
- Возвращаемое значение лямбды (если оно есть) должно быть неявно конвертируемым в возвращаемый тип делегата.
Замечание: лямбда-выражения сами по себе не имеют типа, потому что общая система типов не имеет внутреннего понятия «лямбда-выражение». Однако иногда удобно неформально говорить о «типе» лямбда-выражения. В этих случаях тип относится к типу делегата или типу выражения, в которые преобразуется лямбда-выражение.
Область видимости переменных в лямбда-выражениях
Лямбда-выражение может ссылаться на внешние переменные (см. пост про анонимные методы https://t.iss.one/NetDeveloperDiary/163), которые находятся внутри метода, определяющего лямбда-выражение, или в типе, содержащем лямбда-выражение. Переменные, захваченные таким образом, сохраняются для использования в лямбда-выражении, даже они иначе вышли бы из области видимости и подлежали бы сборке мусора.
Правила области видимости в лямбда-выражениях:
- Внешняя переменная должна быть явно определена, прежде чем она сможет быть использована в лямбда-выражении.
- Перехваченная переменная не будет собираться мусором до тех пор, пока делегат, ссылающийся на нее, не станет пригодным для сборки мусора.
- Переменные, введенные в лямбда-выражении, не видны во включающем выражение методе.
- Лямбда-выражение не может напрямую захватить параметр
- Оператор return в лямбда-выражении не приводит к возврату включающего его метода.
- Лямбда-выражение не может содержать оператор
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
Лямбда-выражения. Окончание
Вывод типа в лямбда-выражениях
При написании лямбда-выражений часто нет необходимости указывать тип для входных параметров, поскольку компилятор может вывести тип на основе тела лямбда выражения, типов параметров и других факторов, описанных в спецификации языка C#. Для большинства стандартных операторов запросов первым вводом является тип элементов в исходной последовательности. Если вы запрашиваете
IEnumerable<Customer>
, то входная переменная приводится к объекту Customer
, что означает, что у вас есть доступ к её методам и свойствам:customers.Where(c => c.City == "London");Общие правила для вывода типа:
- Лямбда должна содержать то же количество параметров, что и тип делегата.
- Каждый входной параметр в лямбда-выражении должен быть неявно преобразован в соответствующий ему параметр делегата.
- Возвращаемое значение лямбды (если оно есть) должно быть неявно конвертируемым в возвращаемый тип делегата.
Замечание: лямбда-выражения сами по себе не имеют типа, потому что общая система типов не имеет внутреннего понятия «лямбда-выражение». Однако иногда удобно неформально говорить о «типе» лямбда-выражения. В этих случаях тип относится к типу делегата или типу выражения, в которые преобразуется лямбда-выражение.
Область видимости переменных в лямбда-выражениях
Лямбда-выражение может ссылаться на внешние переменные (см. пост про анонимные методы https://t.iss.one/NetDeveloperDiary/163), которые находятся внутри метода, определяющего лямбда-выражение, или в типе, содержащем лямбда-выражение. Переменные, захваченные таким образом, сохраняются для использования в лямбда-выражении, даже они иначе вышли бы из области видимости и подлежали бы сборке мусора.
Правила области видимости в лямбда-выражениях:
- Внешняя переменная должна быть явно определена, прежде чем она сможет быть использована в лямбда-выражении.
- Перехваченная переменная не будет собираться мусором до тех пор, пока делегат, ссылающийся на нее, не станет пригодным для сборки мусора.
- Переменные, введенные в лямбда-выражении, не видны во включающем выражение методе.
- Лямбда-выражение не может напрямую захватить параметр
in
, ref
или out
из включающего его метода.- Оператор return в лямбда-выражении не приводит к возврату включающего его метода.
- Лямбда-выражение не может содержать оператор
goto
, break
или continue
, если цель этого оператора находится вне блока лямбда-выражения, и наоборот.Источник: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
День сто сороковой. #ЗаметкиНаПолях
Коллекции в C#
1. Словарь Dictionary<TKey, TValue>
Словарь - это тип коллекции, который полезен, когда вам нужен быстрый поиск по ключам. Например, у вас есть список клиентов, и в рамках задачи вам нужно быстро найти клиента по его ID (или другому уникальному ключу). В списке поиск элемента линейный, и стоимость этой операции составляет O(n). Однако при использовании словаря поиск выполняется стоимостью O(1), т.е. независимо от того, насколько велик словарь, время поиска остается относительно постоянным.
При хранении или извлечении объекта в словаре необходимо указать ключ. Ключ - это значение, которое однозначно идентифицирует объект и не может быть
Для создания словаря нужно указать тип ключей и значений. Например, для словаря клиентов:
Источник: https://programmingwithmosh.com/net/csharp-collections/
Коллекции в C#
1. Словарь Dictionary<TKey, TValue>
Словарь - это тип коллекции, который полезен, когда вам нужен быстрый поиск по ключам. Например, у вас есть список клиентов, и в рамках задачи вам нужно быстро найти клиента по его ID (или другому уникальному ключу). В списке поиск элемента линейный, и стоимость этой операции составляет O(n). Однако при использовании словаря поиск выполняется стоимостью O(1), т.е. независимо от того, насколько велик словарь, время поиска остается относительно постоянным.
При хранении или извлечении объекта в словаре необходимо указать ключ. Ключ - это значение, которое однозначно идентифицирует объект и не может быть
null
. Например, чтобы сохранить объект Customer
в словаре, вы можете использовать CustomerID
в качестве ключа.Для создания словаря нужно указать тип ключей и значений. Например, для словаря клиентов:
var dictionary = new Dictionary<int, Customer>();Наиболее полезные методы и свойства:
dictionary.Add(customer.Id, customer);
…
// Получаем клиента с ID 1234
var customer = dictionary[1234];
// Удаление элемента по ключуПочему поиск в словаре так быстр? Словарь хранит объекты в массиве, но в отличие от списка, в котором объекты добавляются в конец массива (или по указанному индексу), индекс в словаре вычисляется с использованием хеш-функции. При сохранении объекта в словаре, вычисляется хеш ключа с помощью функции
dictionary.Remove(1);
// Очистка словаря
dictionary.Clear();
// Количество элементов
var count = dictionary.Count;
// Проверка на вхождение ключа
var containsKey = dictionary.ContainsKey(1);
// Проверка на вхождение значения
var containsValue = dictionary.ContainsValue(customer1);
// Итерация по ключам
foreach (var key in dictionary.Keys)
Console.WriteLine(dictionary[key]);
// Итерация по значениям
foreach (var value in dictionary.Values)
Console.WriteLine(value);
// Итерация по парам ключ-значение
foreach (var keyValuePair in dictionary)
{
Console.WriteLine(keyValuePair.Key);
Console.WriteLine(keyValuePair.Value);
}
GetHashCode
. Затем хэш корректируется под размер массива, чтобы вычислить индекс. При поиске объекта по ключу, метод GetHashCode
снова используется для вычисления хеша и индекса. Поэтому, в отличие от списков, поиск объекта в словаре не требует сканирования каждого объекта и независимо от того, насколько велик словарь, он останется чрезвычайно быстрым.Источник: https://programmingwithmosh.com/net/csharp-collections/
День сто сорок первый. #ЗаметкиНаПолях
Коллекции в C#
2. HashSet<T>
Создание и использование:
- Инициализация:
- Пересечение множеств (изменяет hashSet):
- Симметричная разница (изменяет hashSet), элементы из hashSet или из another, но не из обоих:
Коллекции в C#
2. HashSet<T>
HashSet
представляет набор уникальных элементов, как математическое множество (например, {1, 2, 3}
). Набор не может содержать дубликаты, а порядок элементов не имеет значения, т.е. {1, 2, 3}
и {3, 2, 1}
равны.HashSet
используется, когда вам нужен быстрый поиск в наборе уникальных элементов. Например, при обработке списка заказов для каждого заказа вам нужно быстро проверить, входит ли код поставщика в список корректных кодов.HashSet
, похож на Dictionary
, представляет собой коллекцию на основе хеша, поэтому поиск выполняется очень быстро за время O(1). Но, в отличие от словаря, он хранит только значения без ключей. Таким образом, каждый объект должен быть уникальным, и это определяется по GetHashCode
. Т.е., если вы собираетесь хранить пользовательские типы в наборе, вам необходимо переопределить методы GetHashCode
и Equals
в вашем типе.Создание и использование:
- Инициализация:
var hashSet = new HashSet<int>() { 1, 2, 3 };- Добавление:
hashSet.Add(4);- Удаление:
hashSet.Remove(3);- Очистка:
hashSet.Clear();- Проверка наличия элемента:
var contains = hashSet.Contains(1);- Количество элементов:
var count = hashSet.Count;
HashSet
предоставляет набор математических операций для работы с множествами. Следующие методы имеют аналоги в LINQ для любых коллекций IEnumerable<T>:- Пересечение множеств (изменяет hashSet):
hashSet.IntersectWith(another);- Объединение множеств (изменяет hashSet):
hashSet.UnionWith(another);- Удаляет все элементы another из hashSet:
hashSet.ExceptWith(another);Следующие методы НЕ имеют аналогов в LINQ для обычных коллекций:
- Симметричная разница (изменяет hashSet), элементы из hashSet или из another, но не из обоих:
hashSet.SymmetricExceptWith(another);- Является ли hashSet надмножеством another:
var isSupersetOf = hashSet.IsSupersetOf(another);- Является ли hashSet строгим надмножеством another:
var isSupersetOf = hashSet.IsProperSupersetOf(another);- Является ли hashSet подмножеством another:
var isSubsetOf = hashSet.IsSubsetOf(another);- Является ли hashSet строгим подмножеством another:
var isSubsetOf = hashSet.IsProperSubsetOf(another);- Содержит ли hashSet те же элементы, что и another:
var equals = hashSet.SetEquals(another);- Есть ли у hashSet и another одинаковые элементы:
var overlaps = hashSet.Overlaps(another);Источник: https://programmingwithmosh.com/net/csharp-collections/
День сто сорок второй. #ЧтоНовенького
Visual Studio 2019 версии 16.2
Вышло превью Visual Studio 2019 версии 16.2. Версия доступна для загрузки с VisualStudio.com, или, если у вас отмечена установка превью версий, просто щелкните значок уведомления в Visual Studio для обновления.
Поддержка Microsoft Edge Insider
Теперь Visual Studio позволяет отлаживать JavaScript в новом браузере Microsoft Edge Insider для проектов ASP.NET и ASP.NET Core. Для этого просто установите браузер, установите точку останова в JavaScript приложении и начните сеанс отладки. Visual Studio запустит новое окно браузера с включенной отладкой, что позволит вам шагать по коду JavaScript в Visual Studio (см. картинку выше).
Visual Studio 2019 версии 16.2
Вышло превью Visual Studio 2019 версии 16.2. Версия доступна для загрузки с VisualStudio.com, или, если у вас отмечена установка превью версий, просто щелкните значок уведомления в Visual Studio для обновления.
Поддержка Microsoft Edge Insider
Теперь Visual Studio позволяет отлаживать JavaScript в новом браузере Microsoft Edge Insider для проектов ASP.NET и ASP.NET Core. Для этого просто установите браузер, установите точку останова в JavaScript приложении и начните сеанс отладки. Visual Studio запустит новое окно браузера с включенной отладкой, что позволит вам шагать по коду JavaScript в Visual Studio (см. картинку выше).
Улучшения помощников
- «По просьбам трудящихся» возвращена команда Sort Usings, и она отделена Remove Usings. Sort Usings можно найти в меню Edit > IntelliSense.
- Добавлена возможность преобразовывать операторы switch в выражения. Поскольку выражения-переключатели являются новой функцией C# 8.0, необходимо убедиться, что вы используете самую последнюю версию языка. Поместите курсор на ключевое слово switch, нажмите Ctrl+., в выпадающем меню Quick Actions and Refactorings выберите Convert switch statement to expression.
Улучшение установщика Visual Studio
Установщик Visual Studio теперь будет лучше определять размер свободного места в зависимости от того, что вы уже установили на своем компьютере. Это означает, что, если требуемый объем пространства больше, чем доступно, установка отменяется.
Источник: https://devblogs.microsoft.com/visualstudio/visual-studio-2019-version-16-2-preview-2/
- «По просьбам трудящихся» возвращена команда Sort Usings, и она отделена Remove Usings. Sort Usings можно найти в меню Edit > IntelliSense.
- Добавлена возможность преобразовывать операторы switch в выражения. Поскольку выражения-переключатели являются новой функцией C# 8.0, необходимо убедиться, что вы используете самую последнюю версию языка. Поместите курсор на ключевое слово switch, нажмите Ctrl+., в выпадающем меню Quick Actions and Refactorings выберите Convert switch statement to expression.
Улучшение установщика Visual Studio
Установщик Visual Studio теперь будет лучше определять размер свободного места в зависимости от того, что вы уже установили на своем компьютере. Это означает, что, если требуемый объем пространства больше, чем доступно, установка отменяется.
Источник: https://devblogs.microsoft.com/visualstudio/visual-studio-2019-version-16-2-preview-2/
День сто сорок третий. #ЗаметкиНаПолях
Коллекции в C#
3. Стек
Стек - это тип коллекции с поведением «последний пришел - первым вышел» (LIFO). Мы часто используем стеки в сценариях, где нам нужно предоставить пользователю способ вернуться назад. Подумайте о своем браузере. Когда вы переходите на разные веб-сайты, эти адреса, которые вы посещаете, помещаются в стек. Затем, когда вы нажимаете кнопку «Назад», элемент в стеке (который представляет текущий адрес в браузере) извлекается, и теперь мы можем получить последний адрес, который вы посетили, из элемента в стеке. Функция отмены в приложениях также реализована с использованием стека.
Использование стека:
Источник: https://programmingwithmosh.com/net/csharp-collections/
Коллекции в C#
3. Стек
Стек - это тип коллекции с поведением «последний пришел - первым вышел» (LIFO). Мы часто используем стеки в сценариях, где нам нужно предоставить пользователю способ вернуться назад. Подумайте о своем браузере. Когда вы переходите на разные веб-сайты, эти адреса, которые вы посещаете, помещаются в стек. Затем, когда вы нажимаете кнопку «Назад», элемент в стеке (который представляет текущий адрес в браузере) извлекается, и теперь мы можем получить последний адрес, который вы посетили, из элемента в стеке. Функция отмены в приложениях также реализована с использованием стека.
Использование стека:
var stack = new Stack<string>();Внутренне стек реализован с использованием массива. Поскольку массивы в C# имеют фиксированный размер, когда вы помещаете элементы в стек, может потребоваться увеличить его емкость путем выделения большего массива и копирования существующих элементов в новый массив. Если выделения не требуется, операция
// Размещение элемента в стеке
stack.Push("https://www.google.com");
// Проверка вхождения элемента
var contains = stack.Contains("https://www.google.com");
// Извлечение элемента из вершины стека
var top = stack.Pop();
// Просмотр элемента из вершины стека без извлечения
var top = stack.Peek();
// Количество элементов
var count = stack.Count;
// Очистка
stack.Clear();
Push
выполняется за время O(1); в противном случае, при условии, что в стеке есть n элементов, все эти элементы необходимо скопировать в новый массив. Это приводит к выполнению операции за время O(n). Pop
– за время O(1). Contains
- O(n).Источник: https://programmingwithmosh.com/net/csharp-collections/
День сто сорок четвёртый. #ЗаметкиНаПолях
Коллекции в C#
4. Очередь
Очередь представляет коллекцию с поведением «первым пришел - первым обслужен» (FIFO). Очереди используются, когда нужно обрабатывать элементы по мере их поступления.
Основные операции:
-
-
-
Ёмкость
Использование:
используются
Источники:
- https://programmingwithmosh.com/net/csharp-collections/
- https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.queue
Коллекции в C#
4. Очередь
Очередь представляет коллекцию с поведением «первым пришел - первым обслужен» (FIFO). Очереди используются, когда нужно обрабатывать элементы по мере их поступления.
Queue<T>
реализует обобщённую очередь в виде циклического массива. Объекты добавляются с одного конца и извлекаются с другого. Очереди и стеки полезны, когда вам нужно временное хранилище информации (когда вы можете отказаться от элемента после получения его значения). Используйте очередь, если вам нужен доступ к информации в том же порядке, в котором она хранится в коллекции. Основные операции:
-
Enqueue
: добавление элемента в конец очереди;-
Dequeue
: извлечение элемента из начала очереди;-
Peek
: просмотр элемента из начала очереди без извлечения.Ёмкость
Queue<T>
- это количество элементов, которые она может содержать. По мере добавления элементов ёмкость автоматически увеличивается при необходимости путем перераспределения внутреннего массива. Емкость можно уменьшить, вызвав метод TrimExcess.Queue<T>
допускает значение NULL
для ссылочных типов и допускает дублирование элементов.Использование:
var queue = new Queue<string>();Если нужен одновременный доступ к коллекции из нескольких потоков,
// добавление
queue.Enqueue("transaction1");
// проверка вхождения элемента
var contains = queue.Contains("transaction1");
// извлечение
var front = queue.Dequeue();
// просмотр первого элемента
var top = queue.Peek();
// очистка очереди
queue.Clear();
// количество элементов
var count = queue.Count;
используются
ConcurrentQueue<T>
для очереди или ConcurrentStack<T>
для стека.Источники:
- https://programmingwithmosh.com/net/csharp-collections/
- https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.queue
День сто сорок пятый. #ЗаметкиНаПолях
Коллекции в C#
5. Битовый массив BitArray
Битовый массив управляет компактным массивом значений битов, которые представлены как логические значения, где
Класс
- https://docs.microsoft.com/ru-ru/dotnet/api/system.collections.bitarray
Коллекции в C#
5. Битовый массив BitArray
Битовый массив управляет компактным массивом значений битов, которые представлены как логические значения, где
true
указывает, что бит включен (1
), а false
указывает, что бит выключен (0
).Класс
BitArray
- это класс коллекции, емкость которого всегда равна количеству. Элементы добавляются в BitArray
путем увеличения свойства Length
; удаляются уменьшением свойства Length
. // Инициализация (все значения false)Класс
var ba1 = new BitArray(16);
// Инициализация массивом байтов
// 16 элементов: 1й байт - 0-7, 2й байт - 8-15
byte[] bt = new byte[] { 10, 64 };
var ba2 = new BitArray(bt);
// Количество элементов (16)
var cnt = ba2.Length;
// Установка отдельного значения
ba1[13] = true;
BitArray
предоставляет методы, которых нет в других коллекциях, в том числе те, которые позволяют одновременно изменять несколько элементов с помощью фильтров, таких как And
, Or
, Xor
, Not
и SetAll
:// изменение значений на противоположныеИсточники:
ba1.Not();
// Побитовое И (изменяет ba1)
ba1.And(ba2);
// Побитовое ИЛИ (изменяет ba1)
ba1.Or(ba2);
// Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ (изменяет ba1)
ba1.Xor(ba2);
// Установка всех значений
ba1.SetAll(true);
- https://docs.microsoft.com/ru-ru/dotnet/api/system.collections.bitarray
День сто сорок шестой. #ЗаметкиНаПолях
Коллекции в C#
6. Сортировка коллекций
В .Net реализованы следующие основные типы отсортированных коллекций:
1. SortedSet<T>
Поддерживает отсортированный порядок, не влияя на производительность вставки и удаления. Повторяющиеся элементы не допускаются. Изменение отсортированных значений существующих элементов не поддерживается и может привести к неожиданному поведению. Потокобезопасная версия -
2. SortedList<TKey,TValue> и SortedDictionary<TKey,TValue>
- SortedList использует меньше памяти.
- SortedDictionary быстрее вставляет и удаляет несортированные данные (O(log n) против O(n) для SortedList).
- Если список заполняется сразу из отсортированных данных, SortedList работает быстрее.
SortedList поддерживает эффективный индексированный поиск ключей и значений через коллекции, возвращаемые свойствами
Объекты ключей должны быть неизменяемыми, если они используются в качестве ключей в SortedList или SortedDictionary. Каждый ключ в должен быть уникальным, не нулевым. Значение может быть нулевым, если
SortedList и SortedDictionary требуют реализации компаратора для сортировки и выполнения сравнений. Компаратор по умолчанию
Когда элементы добавляются в SortedList, емкость автоматически увеличивается по мере необходимости путем перераспределения внутреннего массива. Емкость можно уменьшить, вызвав
Оператор foreach перебирает объекты типа элементов в коллекции. Поскольку элементы SortedList и SortedDictionary являются парами ключ/значение, foreach перебирает элементы
- Sort(IComparer<T> comparer)
Cортирует все элементы, используя указанный компаратор.
- Sort(int index, int count, IComparer<T> comparer)
Cортирует элементы в диапазоне (count элементов, начиная с index), используя указанный компаратор.
- Sort()
Сортирует все элементы, используя компаратор по умолчанию.
- Sort(Comparison<T> cmp)
Сортирует все элементы списка, используя делегат сравнения. Делегат сравнения вида
Например:
Коллекции в C#
6. Сортировка коллекций
В .Net реализованы следующие основные типы отсортированных коллекций:
1. SortedSet<T>
Поддерживает отсортированный порядок, не влияя на производительность вставки и удаления. Повторяющиеся элементы не допускаются. Изменение отсортированных значений существующих элементов не поддерживается и может привести к неожиданному поведению. Потокобезопасная версия -
ImmutableSortedSet<T>
.2. SortedList<TKey,TValue> и SortedDictionary<TKey,TValue>
SortedList<TKey, TValue>
- это массив пар ключ/значение с поиском за время O(log n). В этом он похож на SortedDictionary<TKey, TValue>
. Два класса имеют похожие объектные модели, и оба имеют время извлечения O(log n). Различаются они в использовании памяти и скорости вставки и удаления:- SortedList использует меньше памяти.
- SortedDictionary быстрее вставляет и удаляет несортированные данные (O(log n) против O(n) для SortedList).
- Если список заполняется сразу из отсортированных данных, SortedList работает быстрее.
SortedList поддерживает эффективный индексированный поиск ключей и значений через коллекции, возвращаемые свойствами
Keys
и Values
. Нет необходимости повторно создавать списки при обращении к свойствам, поскольку они являются просто оболочками для внутренних массивов ключей и значений. В следующем коде показано использование индексатора свойства Values
для извлечения значения из отсортированного списка строк:string v = mySortedList.Values[3];Элементы SortedList могут быть извлечены как объекты
KeyValuePair<TKey, TValue>
, для SortedDictionary – как KeyValuePair<TKey, TValue>
или как необобщённые объекты DictionaryEntry
.Объекты ключей должны быть неизменяемыми, если они используются в качестве ключей в SortedList или SortedDictionary. Каждый ключ в должен быть уникальным, не нулевым. Значение может быть нулевым, если
TValue
- ссылочный тип.SortedList и SortedDictionary требуют реализации компаратора для сортировки и выполнения сравнений. Компаратор по умолчанию
Comparer<T>.Default
проверяет, реализует ли тип ключа IComparable<T>
, и использует эту реализацию, если она доступна. Если нет, он проверяет, реализует ли тип ключа IComparable
. Если тип ключа не реализует ни один из этих интерфейсов, вы можете указать параметр-компаратор, реализующий IComparer<T>
, в перегруженной версии конструктора.Когда элементы добавляются в SortedList, емкость автоматически увеличивается по мере необходимости путем перераспределения внутреннего массива. Емкость можно уменьшить, вызвав
TrimExcess
или явно указав свойство Capacity
. Уменьшение емкости перераспределяет память и копирует все элементы в SortedList.Оператор foreach перебирает объекты типа элементов в коллекции. Поскольку элементы SortedList и SortedDictionary являются парами ключ/значение, foreach перебирает элементы
KeyValuePair<TKey, TValue>
:foreach (KeyValuePair<int, string> kvp в sortedList)Кроме того, можно использовать метод
{
Console.WriteLine("{0} = {1}", kvp.Key, kvp.Value);
}
Sort
для несортированных списков:- Sort(IComparer<T> comparer)
Cортирует все элементы, используя указанный компаратор.
- Sort(int index, int count, IComparer<T> comparer)
Cортирует элементы в диапазоне (count элементов, начиная с index), используя указанный компаратор.
- Sort()
Сортирует все элементы, используя компаратор по умолчанию.
- Sort(Comparison<T> cmp)
Сортирует все элементы списка, используя делегат сравнения. Делегат сравнения вида
int Comparison<in T>(T x, T y)
должен возвращать значение меньше 0, если x<y, больше 0, если x>y и 0, если x=y.Например:
var list = new List<int>{2,4,3,1};Источник: https://docs.microsoft.com/ru-ru/dotnet/api/system.collections.generic
// сортировка по возрастанию (по умолчанию)
list.Sort(); // 1,2,3,4
// используем лямбда-выражение для сортировки по убыванию
list.Sort((x,y) => y-x); // 4,3,2,1
День сто сорок седьмой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по .NET
1. Что такое .NET Framework?
.NET Framework - это набор многократно используемых библиотек (коллекций классов), предоставляемый Microsoft для использования в других приложениях .Net, а также для разработки, создания и развертывания многих типов приложений на платформе Windows, включая:
- Консольные приложения
- Приложения Windows Forms
- Приложения Windows Presentation Foundation (WPF)
- Веб-приложения
- Веб-сервисы
- Службы Windows
- Сервис-ориентированные приложения с использованием Windows Communications Foundation (WCF)
- Приложения с поддержкой рабочих процессов, использующие Windows Workflow Foundation (WF)
Работает в основном на операционной системе Microsoft Windows.
Компиляция программы .NET
Что на самом деле происходит, когда мы компилируем программу .NET?
- Созданный exe-файл не содержит исполняемого кода, это код на MicroSoft Intermediate Language (MSIL).
- Когда вы запускаете EXE-файл, запускается общеязыковая среда выполнения (Common Language Runtime или CLR) и инструкции IL выполняются CLR на машинном языке.
- CLR предлагает компилятор Just In Time (JIT), который переводит IL на машинный язык.
См. рисунок ниже.
Таким образом, процесс программирования проходит как:
- Программа пишется на C#, VB.Net и других языках.
- Код компилируется в IL с помощью компилятора языка (csc.exe, vbc.exe и т.д.).
- При запуске программы на IL, запускается CLR, которая, используя JIT, преобразует IL в машинный код по мере выполнения программы.
Ядро .NET Framework
- Сервисы Приложений
- Библиотеки базовых классов
- Общеязыковая Среда Выполнения (Common Language Runtime)
- Сборщик Мусора (Garbage Collector)
- Общая Система Типов (Common Type System)
- Общеязыковая Спецификация (Common Language Specification)
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по .NET
1. Что такое .NET Framework?
.NET Framework - это набор многократно используемых библиотек (коллекций классов), предоставляемый Microsoft для использования в других приложениях .Net, а также для разработки, создания и развертывания многих типов приложений на платформе Windows, включая:
- Консольные приложения
- Приложения Windows Forms
- Приложения Windows Presentation Foundation (WPF)
- Веб-приложения
- Веб-сервисы
- Службы Windows
- Сервис-ориентированные приложения с использованием Windows Communications Foundation (WCF)
- Приложения с поддержкой рабочих процессов, использующие Windows Workflow Foundation (WF)
Работает в основном на операционной системе Microsoft Windows.
Компиляция программы .NET
Что на самом деле происходит, когда мы компилируем программу .NET?
- Созданный exe-файл не содержит исполняемого кода, это код на MicroSoft Intermediate Language (MSIL).
- Когда вы запускаете EXE-файл, запускается общеязыковая среда выполнения (Common Language Runtime или CLR) и инструкции IL выполняются CLR на машинном языке.
- CLR предлагает компилятор Just In Time (JIT), который переводит IL на машинный язык.
См. рисунок ниже.
Таким образом, процесс программирования проходит как:
- Программа пишется на C#, VB.Net и других языках.
- Код компилируется в IL с помощью компилятора языка (csc.exe, vbc.exe и т.д.).
- При запуске программы на IL, запускается CLR, которая, используя JIT, преобразует IL в машинный код по мере выполнения программы.
Ядро .NET Framework
- Сервисы Приложений
- Библиотеки базовых классов
- Общеязыковая Среда Выполнения (Common Language Runtime)
- Сборщик Мусора (Garbage Collector)
- Общая Система Типов (Common Type System)
- Общеязыковая Спецификация (Common Language Specification)
Источник: 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.
День сто сорок восьмой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по .NET
2. Что такое CLR?
CLR (Common Language Runtime) – Общеязыковая Среда Исполнения. Она работает как слой между операционной системой и приложениями, написанными на языках .Net, которые соответствуют Общеязыковой Спецификации (CLS). Основной функцией CLR является преобразование управляемого кода в машинный код и последующее выполнение программы. Управляемый код компилируется только тогда, когда это необходимо, то есть он преобразует соответствующие инструкции при вызове каждой функции. Компиляция JIT позволяет преобразовать промежуточный язык (MSIL) в машинный код по требованию во время выполнения приложения.
Во время выполнения приложения .Net управление переходит к операционной системе, она создает процесс для загрузки CLR. Программа, используемая операционной системой для загрузки CLR, называется средой выполнения, которая отличается в зависимости от типа приложения: настольное, веб-приложение и т.д.
Среда выполнения CLR имеет набор сервисов:
1. Распознаватель Сборок (Assembly Resolver)
Читает манифест приложения, определяет приватную или общую сборку, необходимую для выполнения приложения и передаёт запрос загрузчику сборок.
2. Загрузчик Сборок (Assembly Loader)
Загружает сборку в процесс приложения на основе инструкций распознавателя сборок.
3. Инспектор Типов (Type Checker)
Проверяет типы, используемые в приложении, на соответствие со стандартами CTS или CLS, поддерживаемыми CLR, что обеспечивает безопасность типов.
4. Маршаллер COM (COM marshaller)
Обеспечивает связь с COM-компонентами.
5. Диспетчер Отладки (Debug Manager)
Активирует утилиту отладчика для поддержки построчного выполнения. Разработчик может вносить изменения, не прерывая отладки приложения.
6. Поддержка Потоков (Thread Support)
Управляет потоками выполнения в процессе приложения.
7. IL Компилятор (IL to Native compiler)
Компилятор IL в машинный язык называется JIT-компилятором (Just-In-Time). Он преобразует IL-код в машинный код операционной системы во время выполнения.
8. Менеджер Исключений (Exception Manager)
Обрабатывает исключения, генерируемые приложением, выполняя блоки catch, либо при отсутствии обработчика завершает работу приложения.
9. Сборщик Мусора (Garbage Collector)
Освобождает память от неиспользуемых объектов, это обеспечивает автоматическое управление памятью.
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по .NET
2. Что такое CLR?
CLR (Common Language Runtime) – Общеязыковая Среда Исполнения. Она работает как слой между операционной системой и приложениями, написанными на языках .Net, которые соответствуют Общеязыковой Спецификации (CLS). Основной функцией CLR является преобразование управляемого кода в машинный код и последующее выполнение программы. Управляемый код компилируется только тогда, когда это необходимо, то есть он преобразует соответствующие инструкции при вызове каждой функции. Компиляция JIT позволяет преобразовать промежуточный язык (MSIL) в машинный код по требованию во время выполнения приложения.
Во время выполнения приложения .Net управление переходит к операционной системе, она создает процесс для загрузки CLR. Программа, используемая операционной системой для загрузки CLR, называется средой выполнения, которая отличается в зависимости от типа приложения: настольное, веб-приложение и т.д.
Среда выполнения CLR имеет набор сервисов:
1. Распознаватель Сборок (Assembly Resolver)
Читает манифест приложения, определяет приватную или общую сборку, необходимую для выполнения приложения и передаёт запрос загрузчику сборок.
2. Загрузчик Сборок (Assembly Loader)
Загружает сборку в процесс приложения на основе инструкций распознавателя сборок.
3. Инспектор Типов (Type Checker)
Проверяет типы, используемые в приложении, на соответствие со стандартами CTS или CLS, поддерживаемыми CLR, что обеспечивает безопасность типов.
4. Маршаллер COM (COM marshaller)
Обеспечивает связь с COM-компонентами.
5. Диспетчер Отладки (Debug Manager)
Активирует утилиту отладчика для поддержки построчного выполнения. Разработчик может вносить изменения, не прерывая отладки приложения.
6. Поддержка Потоков (Thread Support)
Управляет потоками выполнения в процессе приложения.
7. IL Компилятор (IL to Native compiler)
Компилятор IL в машинный язык называется JIT-компилятором (Just-In-Time). Он преобразует IL-код в машинный код операционной системы во время выполнения.
8. Менеджер Исключений (Exception Manager)
Обрабатывает исключения, генерируемые приложением, выполняя блоки catch, либо при отсутствии обработчика завершает работу приложения.
9. Сборщик Мусора (Garbage Collector)
Освобождает память от неиспользуемых объектов, это обеспечивает автоматическое управление памятью.
Источник: https://www.c-sharpcorner.com
👍1
День сто сорок девятый. #ЗаметкиНаПолях
Отражение. Начало
Отражение предоставляет объекты (типа
Вот простой пример отражения с использованием статического метода
- Получение доступа к атрибутам в метаданных программы.
- Изучение и создание экземпляров типов в сборке.
- Создание новых типов во время выполнения. Используются классы из
- Позднее связывание, доступ к методам типов, созданных во время выполнения.
Продолжение следует…
Источник: https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/concepts/reflection
Отражение. Начало
Отражение предоставляет объекты (типа
Type
), которые описывают сборки, модули и типы. Используется для динамического создания экземпляра типа, привязки типа к существующему объекту или получения типа из существующего объекта и вызова его методов или доступа к его полям и свойствам. Если вы используете атрибуты в своем коде, отражение позволяет вам получить к ним доступ. Вот простой пример отражения с использованием статического метода
GetType
, унаследованного всеми типами из базового класса Object
, для получения типа переменной:// Получение информации о типеСценарии использования:
int i = 42;
System.Type type = i.GetType();
System.Console.WriteLine(type);
// Вывод: System.Int32
// Получение информации о сборке
System.Reflection.Assembly info = typeof(System.Int32).Assembly;
System.Console.WriteLine(info);
// Вывод:
// mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- Получение доступа к атрибутам в метаданных программы.
- Изучение и создание экземпляров типов в сборке.
- Создание новых типов во время выполнения. Используются классы из
System.Reflection.Emit
.- Позднее связывание, доступ к методам типов, созданных во время выполнения.
Продолжение следует…
Источник: https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/concepts/reflection
День сто пятидесятый. #ЗаметкиНаПолях
Отражение. Продолжение
Наряду с
Классы System.Reflection:
1. Assembly - распознавание и загрузка сборки, загрузка модулей из манифеста сборки, поиск типа в этой сборке и создание его экземпляров.
2. Module - обнаружение информации, такой как сборка, содержащая модуль и классы в модуле, получение всех глобальных и неглобальные методов, определенных в модуле.
3. ConstructorInfo - обнаружение имени, параметров, модификаторов доступа и подробностей реализации конструктора. Методы GetConstructors и GetConstructor используются для вызова определенного конструктора.
4. MethodInfo - обнаружение имени, типа возвращаемого значения, параметров, модификаторов доступа и подробностей реализации метода. Методы GetMethods и GetMethod используются для вызова определенного метода.
5. FieldInfo – обнаружение имени, модификаторов доступа и подробностей реализации поля, а также для получения или установки значений поля.
6. EventInfo – обнаружение имени, типа данных обработчика событий, пользовательских атрибутов, и т.п. события, а также для добавления или удаления обработчиков событий.
7. PropertyInfo - обнаружение имени, типа данных и состояния свойства, а также для получения или установки значений свойства.
8. ParameterInfo - обнаружение имени параметра, типа данных, является ли параметр входным или выходным, а также положения параметра в сигнатуре метода.
9. CustomAttributeData - обнаружение информации о пользовательских атрибутах, позволяет исследовать атрибуты, не создавая их экземпляры.
Отражение также можно использовать для создания приложений, называемых браузерами типов, которые позволяют пользователям выбирать типы, а затем просматривать информацию об этих типах.
Продолжение следует…
Источник: https://docs.microsoft.com/ru-ru/dotnet/framework/reflection-and-codedom/reflection
Отражение. Продолжение
Наряду с
System.Type
, классы в пространстве имен System.Reflection
позволяют получать информацию о загруженных сборках и определенных в них типах, таких как классы, интерфейсы и структуры. Сборки содержат модули, модули содержат типы, а типы содержат члены. Отражения предоставляет объекты, которые инкапсулируют сборки, модули и типы. Вы можете использовать отражение, чтобы динамически создавать экземпляр типа, связывать тип с существующим объектом или получать тип существующего объекта. Затем вы можете вызвать методы типа или получить доступ к его полям и свойствам.Классы System.Reflection:
1. Assembly - распознавание и загрузка сборки, загрузка модулей из манифеста сборки, поиск типа в этой сборке и создание его экземпляров.
2. Module - обнаружение информации, такой как сборка, содержащая модуль и классы в модуле, получение всех глобальных и неглобальные методов, определенных в модуле.
3. ConstructorInfo - обнаружение имени, параметров, модификаторов доступа и подробностей реализации конструктора. Методы GetConstructors и GetConstructor используются для вызова определенного конструктора.
4. MethodInfo - обнаружение имени, типа возвращаемого значения, параметров, модификаторов доступа и подробностей реализации метода. Методы GetMethods и GetMethod используются для вызова определенного метода.
5. FieldInfo – обнаружение имени, модификаторов доступа и подробностей реализации поля, а также для получения или установки значений поля.
6. EventInfo – обнаружение имени, типа данных обработчика событий, пользовательских атрибутов, и т.п. события, а также для добавления или удаления обработчиков событий.
7. PropertyInfo - обнаружение имени, типа данных и состояния свойства, а также для получения или установки значений свойства.
8. ParameterInfo - обнаружение имени параметра, типа данных, является ли параметр входным или выходным, а также положения параметра в сигнатуре метода.
9. CustomAttributeData - обнаружение информации о пользовательских атрибутах, позволяет исследовать атрибуты, не создавая их экземпляры.
Отражение также можно использовать для создания приложений, называемых браузерами типов, которые позволяют пользователям выбирать типы, а затем просматривать информацию об этих типах.
Продолжение следует…
Источник: https://docs.microsoft.com/ru-ru/dotnet/framework/reflection-and-codedom/reflection
День сто пятьдесят первый. #ЗаметкиНаПолях
Отражение. Окончание
Небольшое приложение для демонстрации возможностей отражения. А заодно протестировать Git в Visual Studio и сервис Azure DevOps (о нём позже). Сразу оговорюсь, с Git практически не работал, по работе больше используем SVN, поэтому, возможно, репозиторий не оформлен по всем канонам. Не судите строго.
В общем, небольшая консольная утилита анализирует сборки .Net в файлах, помещаемых в папку files и выводит информацию о сборке, классах в сборке и членах классов. Информация выводится в консоль и в лог-файл в папке logs.
Если анализируемая сборка ссылается на другие сборки, то необходимые сборки должны быть помещены в папку libs.
Исходный код: https://dev.azure.com/sbenzenko/NetDeveloper/_git/Reflection
Пожалуйста, не стесняйтесь использовать и изменять код, присылать замечания и предложения.
Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 23.
Отражение. Окончание
Небольшое приложение для демонстрации возможностей отражения. А заодно протестировать Git в Visual Studio и сервис Azure DevOps (о нём позже). Сразу оговорюсь, с Git практически не работал, по работе больше используем SVN, поэтому, возможно, репозиторий не оформлен по всем канонам. Не судите строго.
В общем, небольшая консольная утилита анализирует сборки .Net в файлах, помещаемых в папку files и выводит информацию о сборке, классах в сборке и членах классов. Информация выводится в консоль и в лог-файл в папке logs.
Если анализируемая сборка ссылается на другие сборки, то необходимые сборки должны быть помещены в папку libs.
Исходный код: https://dev.azure.com/sbenzenko/NetDeveloper/_git/Reflection
Пожалуйста, не стесняйтесь использовать и изменять код, присылать замечания и предложения.
Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 23.
День сто пятьдесят второй. #МоиИнструменты
Azure DevOps
Этот пост серии Мои Инструменты будет отличаться от остальных, поскольку этим инструментом я только начал пользоваться. То есть, не могу в полной мере назвать его своим. Как обещал, рассказываю про Microsoft Azure DevOps. Его можно найти здесь https://visualstudio.microsoft.com/ru/team-services/
Как видно из ссылки, это сервис больше для командной разработки. Но и индивидуальные разработчики могут найти много полезного. Во-первых, это бесплатный репозиторий Git. Можно создавать как публичные, так и приватные репозитории.
Система создана для управления вашими проектами. Создаёте проект, система сразу же создаёт для него репозиторий, ссылку на который вы можете скопировать, либо (что очень круто) выполнить Git Clone сразу в вашу любимую IDE (Visual Studio, VS Code, PHP Storm, Eclipse, тысячи их…(с)). Соответственно вся информация о репозитории(-ях): Commits, Pushes, Tags и т.п. - тоже доступна на вкладке Repos.
На вкладке Boards доступны различные инструменты управления проектом: Agile, Scrum, вотэтовсё. Можно управлять рабочим процессом, создавать задания, назначать на них исполнителей и отслеживать выполнение. Кроме того, задания можно привязывать к коммитам Git и как в статистике коммитов, так и в статистике заданий, будет отображаться информация о том, какой коммит к какому заданию привязан.
На вкладке Test Plans можно управлять тестированием проекта. Например, указывать группе тестировщиков (или себе на будущее), как надо тестировать тот или иной функционал.
Вкладка Pipelines самая интересная. Позволяет управлять развёртыванием проекта. Например, можно настроить выполнение заданий при каждом коммите: автоматическую сборку проекта, выполнение автоматизированных тестов, выкладывание продакшн кода в облачный сервис и т.п. И если что-то из этого завершится неудачей, вы получите email и это будет отображено в описании проекта. Можно настраивать развёртывание нескольких версий приложения (версии для разработки, стейджинг и продакшн версии) по-разному.
В общем, система очень богатая и полезная. Здесь мы только «поцарапали её поверхность», как говорят у них.
Источник и подробности (на английском): https://www.youtube.com/watch?v=H-R2bCXfz8I
Azure DevOps
Этот пост серии Мои Инструменты будет отличаться от остальных, поскольку этим инструментом я только начал пользоваться. То есть, не могу в полной мере назвать его своим. Как обещал, рассказываю про Microsoft Azure DevOps. Его можно найти здесь https://visualstudio.microsoft.com/ru/team-services/
Как видно из ссылки, это сервис больше для командной разработки. Но и индивидуальные разработчики могут найти много полезного. Во-первых, это бесплатный репозиторий Git. Можно создавать как публичные, так и приватные репозитории.
Система создана для управления вашими проектами. Создаёте проект, система сразу же создаёт для него репозиторий, ссылку на который вы можете скопировать, либо (что очень круто) выполнить Git Clone сразу в вашу любимую IDE (Visual Studio, VS Code, PHP Storm, Eclipse, тысячи их…(с)). Соответственно вся информация о репозитории(-ях): Commits, Pushes, Tags и т.п. - тоже доступна на вкладке Repos.
На вкладке Boards доступны различные инструменты управления проектом: Agile, Scrum, вотэтовсё. Можно управлять рабочим процессом, создавать задания, назначать на них исполнителей и отслеживать выполнение. Кроме того, задания можно привязывать к коммитам Git и как в статистике коммитов, так и в статистике заданий, будет отображаться информация о том, какой коммит к какому заданию привязан.
На вкладке Test Plans можно управлять тестированием проекта. Например, указывать группе тестировщиков (или себе на будущее), как надо тестировать тот или иной функционал.
Вкладка Pipelines самая интересная. Позволяет управлять развёртыванием проекта. Например, можно настроить выполнение заданий при каждом коммите: автоматическую сборку проекта, выполнение автоматизированных тестов, выкладывание продакшн кода в облачный сервис и т.п. И если что-то из этого завершится неудачей, вы получите email и это будет отображено в описании проекта. Можно настраивать развёртывание нескольких версий приложения (версии для разработки, стейджинг и продакшн версии) по-разному.
В общем, система очень богатая и полезная. Здесь мы только «поцарапали её поверхность», как говорят у них.
Источник и подробности (на английском): https://www.youtube.com/watch?v=H-R2bCXfz8I
День сто пятьдесят третий. #ЗаметкиНаПолях
Решатель судоку
По мотивам давнишнего поста https://t.iss.one/NetDeveloperDiary/83 решил сделать небольшую библиотеку для решения судоку на C#. Код здесь: https://dev.azure.com/sbenzenko/NetDeveloper/_git/SudokuSolver
Краткое описание
Сетка судоку представляет собой двумерный массив типа
Решение задачи (метод SolveSudoku):
1) В методе
2) В цикле пробуем записать в клетку цифры от 1 до 9. В методе
- нет одинаковых цифр в текущем секторе 3х3
- нет одинаковых цифр в текущем столбце
- нет одинаковых цифр в текущей строке
3) Если правила не нарушены, рекурсивно вызываем
Если
В противном случае нужно отменить сделанные изменения:
- устанавливаем значение клетки обратно в
- увеличиваем количество «отмен» в переменной
4) Если мы прошли по циклу в п.2 и ни одно число не подошло, возвращаем
В тестовом проекте (
Примечания:
- Пока нет визуального UI, возможно сделаю позже.
- Решение можно оптимизировать: выполнять поиск доступных цифр в п.2.
Источник и подробности с решением на Python (на английском языке): https://www.youtube.com/watch?v=auK3PSZoidc
Решатель судоку
По мотивам давнишнего поста https://t.iss.one/NetDeveloperDiary/83 решил сделать небольшую библиотеку для решения судоку на C#. Код здесь: https://dev.azure.com/sbenzenko/NetDeveloper/_git/SudokuSolver
Краткое описание
Сетка судоку представляет собой двумерный массив типа
byte
. Первоначально заполняется цифрами из задачи судоку, свободные клетки нулями.Решение задачи (метод SolveSudoku):
1) В методе
FindNextCellToFill
находим следующую свободную клетку (со значением 0). Если метод возвращает -1, значит свободных клеток нет, задача решена.2) В цикле пробуем записать в клетку цифры от 1 до 9. В методе
IsValid
проверяем, не нарушает ли новая цифра правила:- нет одинаковых цифр в текущем секторе 3х3
- нет одинаковых цифр в текущем столбце
- нет одинаковых цифр в текущей строке
3) Если правила не нарушены, рекурсивно вызываем
SolveSudoku
(которая выполняет процедуру для следующей пустой клетки). Если
SolveSudoku
вернёт true
, значит сетка заполнена и задача решена (см. п.1). Выходим из процедуры.В противном случае нужно отменить сделанные изменения:
- устанавливаем значение клетки обратно в
0
,- увеличиваем количество «отмен» в переменной
BackTracks
(для статистики).4) Если мы прошли по циклу в п.2 и ни одно число не подошло, возвращаем
false
, т.е. решений задачи нет.В тестовом проекте (
SudokuSolverTests
) есть три примера решений судоку (лёгкого, среднего и «самого сложного известного»). Они же записаны в консольном проекте SolveSudokuConsole
от простого к сложному. Можете раскомментировать один из них и посмотреть решение. По количеству выводимых «отмен» (Backtracks
) очевидна сложность задачи.Примечания:
- Пока нет визуального UI, возможно сделаю позже.
- Решение можно оптимизировать: выполнять поиск доступных цифр в п.2.
Источник и подробности с решением на Python (на английском языке): https://www.youtube.com/watch?v=auK3PSZoidc
День сто пятьдесят четвёртый. #ЗаметкиНаПолях
Сериализация. Начало
Сериализация - это процесс преобразования объекта в поток байтов для хранения его в памяти, базе данных или файле. Основная цель - сохранить состояние объекта, чтобы иметь возможность воссоздать его при необходимости. Обратный процесс называется десериализацией.
Объект сериализуется в поток, который переносит не только данные, но и информацию о типе объекта, например его версию, имя сборки и языковые стандарты. Из этого потока он может быть сохранен в базе данных, файле или памяти.
Примеры использования:
- отправка объекта в удаленное приложение с помощью веб-службы,
- передача объекта из одного домена в другой,
- передача объекта через брандмауэр в виде строки XML,
- поддержание безопасности при передаче пользовательских данных между приложениями,
- сохранение набора объектов (например, состояние приложения) в качестве «резервной копии»,
- глубокое копирование объектов (об этом позже).
Чтобы сериализовать объект, вам нужен сериализуемый объект, поток, содержащий сериализованный объект, и средство форматирования.
Примените атрибут
Если сериализованный класс содержит ссылки на объекты других классов, помеченные атрибутом
Пример
Метод
Продолжение следует…
Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 24.
- https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/concepts/serialization/
Сериализация. Начало
Сериализация - это процесс преобразования объекта в поток байтов для хранения его в памяти, базе данных или файле. Основная цель - сохранить состояние объекта, чтобы иметь возможность воссоздать его при необходимости. Обратный процесс называется десериализацией.
Объект сериализуется в поток, который переносит не только данные, но и информацию о типе объекта, например его версию, имя сборки и языковые стандарты. Из этого потока он может быть сохранен в базе данных, файле или памяти.
Примеры использования:
- отправка объекта в удаленное приложение с помощью веб-службы,
- передача объекта из одного домена в другой,
- передача объекта через брандмауэр в виде строки XML,
- поддержание безопасности при передаче пользовательских данных между приложениями,
- сохранение набора объектов (например, состояние приложения) в качестве «резервной копии»,
- глубокое копирование объектов (об этом позже).
Чтобы сериализовать объект, вам нужен сериализуемый объект, поток, содержащий сериализованный объект, и средство форматирования.
System.Runtime.Serialization
содержит классы, необходимые для сериализации и десериализации объектов.Примените атрибут
Serializable
к типу, чтобы указать, что экземпляры этого типа могут быть сериализованы. При попытке сериализовать объект, не помеченный атрибутом Serializable
, выбрасывается исключение. Атрибут Serializable не наследуется производными типами.Если сериализованный класс содержит ссылки на объекты других классов, помеченные атрибутом
Serializable
, эти объекты также будут сериализованы.Пример
public static void Main()Метод
{
var objects = new List<string> { "Jeff", "Kristin", "Grant" };
var stream = SerializeToMemory(objects);
stream.Position = 0;
var deserialized = (List<string>)DeserializeFromMemory(stream);
foreach (var s in deserialized)
Console.WriteLine(s);
}
private static Stream SerializeToMemory(object objects)
{
var stream = new MemoryStream();
new BinaryFormatter().Serialize(stream, objects);
return stream;
}
private static object DeserializeFromMemory(Stream stream)
{
return new BinaryFormatter().Deserialize(stream);
}
SerializeToMemory
создаёт объект System.IO.MemoryStream
, чтобы разместить поток сериализованных данных в памяти. Затем используется объект BinaryFormatter
из пространства имён System.Runtime.Serialization.Formatters.Binary
. Этот объект, реализующий интерфейс IFormatter, «умеет» сериализовывать объекты в поток байтов и десериализовывать их из него.Метод
DeserializeFromMemory
использует тот же поток данных из памяти, чтобы выполнить обратные действия.Продолжение следует…
Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 24.
- https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/concepts/serialization/
День сто пятьдесят пятый. #ЗаметкиНаПолях
Сериализация. Продолжение
Управление сериализацией и десериализацией
После назначения типу атрибута
- поле содержит информацию, становящуюся недействительной после десериализации (указатель, дескриптор или некоторую другую структуру данных, специфичную для конкретной среды);
- поле содержит легко обновляемую информацию (которую легко восстановить без десериализации).
Для восстановления такой информации, а также, если необходимо выполнить какие-либо другие действия при сериализации/десериализации, в типе можно определить методы, помеченные атрибутами
StreamingContext
Это структура, имеющая два открытых свойства только для чтения.
1. Context – ссылка на объект типа
2. State – набор битовых флагов, указывающих источник или приёмник сериализуемых/десериализуемых данных:
- CrossProcess – другой процесс на той же машине;
- CrossMachines – источник/приёмник - другая машина;
- File – источник/приёмник – файл (десериализовать, возможно, будет другой процесс);
- Persistence - источник/приёмник – база данных;
- Remoting – данные являются удалёнными по отношению к текущему контексту;
- Other - источник/приёмник неизвестны;
- Clone – точное копирование объекта (об этом далее);
- CrossAppDomain - источник/приёмник – другой домен приложений;
- All - источник/приёмник – любой контекст (по умолчанию).
Окончание следует…
Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 24.
Сериализация. Продолжение
Управление сериализацией и десериализацией
После назначения типу атрибута
Serializable
все экземпляры его полей (открытые, закрытые, защищённые и т.п.) становятся сериализуемыми. Но можно указать некоторые поля, не подлежащие сериализации с помощью атрибута NonSerialized
. Это делается, например, в следующих случаях:- поле содержит информацию, становящуюся недействительной после десериализации (указатель, дескриптор или некоторую другую структуру данных, специфичную для конкретной среды);
- поле содержит легко обновляемую информацию (которую легко восстановить без десериализации).
Для восстановления такой информации, а также, если необходимо выполнить какие-либо другие действия при сериализации/десериализации, в типе можно определить методы, помеченные атрибутами
OnSerializing
, OnSerialized
, OnDeserializing
, OnDeserialized
:[OnDeserialized]Если после сериализации к типу было добавлено поле, десериализация экземпляра выбросит исключение. В этом случае к новому полю можно добавить атрибут
private void OnDeserialized(StreamingContext context) { … }
OptionalField
. Тогда при десериализации в случае отсутствия данных для этого поля исключения выброшено не будет.StreamingContext
Это структура, имеющая два открытых свойства только для чтения.
1. Context – ссылка на объект типа
object
, содержащий нужный пользователю контекст (используется при переопределении объектов форматирования, реализующих IFormatter
).2. State – набор битовых флагов, указывающих источник или приёмник сериализуемых/десериализуемых данных:
- CrossProcess – другой процесс на той же машине;
- CrossMachines – источник/приёмник - другая машина;
- File – источник/приёмник – файл (десериализовать, возможно, будет другой процесс);
- Persistence - источник/приёмник – база данных;
- Remoting – данные являются удалёнными по отношению к текущему контексту;
- Other - источник/приёмник неизвестны;
- Clone – точное копирование объекта (об этом далее);
- CrossAppDomain - источник/приёмник – другой домен приложений;
- All - источник/приёмник – любой контекст (по умолчанию).
Окончание следует…
Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 24.
День сто пятьдесят шестой. #ЗаметкиНаПолях
Сериализация. Окончание
Пример использования для глубокого копирования
При создании копии объекта возникает проблема с тем, что создаётся поверхностная копия. Даже метод
Одним из способов решить эту проблему, то есть создать глубокую копию объекта, будет использование сериализации. Следующий класс создаёт метод-расширение для глубокого копирования объектов через сериализацию. Замечания:
- объекты копирования должны быть помечены атрибутом
- мы используем упомянутый выше класс
Рассмотрим пример использования этого метода расширения. Допустим, у нас есть простой класс:
Сериализация. Окончание
Пример использования для глубокого копирования
При создании копии объекта возникает проблема с тем, что создаётся поверхностная копия. Даже метод
MemberwiseClone
в System.Object
создает поверхностную копию нового объекта. Копирование объекта выполняется свойство за свойством, если свойство является значимым типом, то копируются данные по битам, а если свойство является ссылочным типом, то копируется ссылка на исходный объект. Другими словами, поле или свойство объекта-клона будет ссылаться на тот же объект.Одним из способов решить эту проблему, то есть создать глубокую копию объекта, будет использование сериализации. Следующий класс создаёт метод-расширение для глубокого копирования объектов через сериализацию. Замечания:
- объекты копирования должны быть помечены атрибутом
Serializable
;- мы используем упомянутый выше класс
StreamingContext
, задавая его свойству State значение StreamingContextStates.Clone
(то есть мы сериализуем объект с целью его копирования).public static class ObjectExtension
{
public static T DeepCopy<T>(this T objSource)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Context = new StreamingContext(StreamingContextStates.Clone);
formatter.Serialize(stream, objSource);
stream.Position = 0;
return (T)formatter.Deserialize(stream);
}
}
}
Рассмотрим пример использования этого метода расширения. Допустим, у нас есть простой класс:
[Serializable]В примере ниже мы составляем список объектов этого класса. Затем делаем поверхностную копию этого списка, а затем глубокую копию. Отличие в том, что, если изменить значение свойства одного из объектов, то изменение затронет как изначальный список, так и его поверхностную копию. А вот глубокая копия останется неизменной:
private class Person
{
public string Name { get; set; }
}
var jeff = new Person { Name = "Jeff" };Если вывести в консоль значения свойств Name объектов из каждого списка, мы получим:
var kris = new Person { Name = "Kristin" };
// изначальный список
var persons = new List<Person> { jeff, kris };
// поверхностная копия
var shallowCopy = new List<Person>(persons);
// глубокая копия
var deepCopy = objects.DeepCopy();
// изменяем свойство объекта
jeff.Name = "Bob";
persons: Bob, KristinИсточник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 24.
shallowCopy: Bob, Kristin
deepCopy: Jeff, Kristin
День сто пятьдесят седьмой. #Оффтоп
Рефакторинг унаследованного (легаси) кода.
Как обычно, гуляя по ютубу, наткнулся на вот такое интересное видео https://www.youtube.com/watch?v=XejfFBvODxc
Лекция разработчика из Додо Пиццы (ВНЕЗАПНО!) по рефакторингу. Как исправлять, поддерживать и покрывать тестами код, при этом сохраняя старый код и не рискуя ничего поломать. Далеко не со всеми методами лично я согласен, однако, есть и некоторые интересные приёмчики.
Коротко об основных приёмах:
1. Сохраняем сигнатуры
Даже самые ужасные на вид сигнатуры из легаси методов безопаснее просто скопировать для использования в новых методах, чем производить какие-либо манипуляции с аргументами.
2. Метод/класс росток
Если нужно внести дополнение в старый метод, вставляем туда новый метод, который покрываем тестами. Хотя бы новый код будет протестирован.
3. Метод/класс обёртка
Для добавления функциональности к старому методу создаём новый метод, в котором вызываем старый и добавляем новый код. В отношении классов используем шаблон Декоратор: наследуем от старого класса, добавляя функциональность.
4. Извлечение и переопределение
Если метод использует функциональность, которую нельзя или трудно протестировать явно (запись в консоль/файл/БД, отправка писем клиентам, отправка платежей и т.п.), извлекаем вызов каждого такого метода в новый метод, который делаем
Рефакторинг унаследованного (легаси) кода.
Как обычно, гуляя по ютубу, наткнулся на вот такое интересное видео https://www.youtube.com/watch?v=XejfFBvODxc
Лекция разработчика из Додо Пиццы (ВНЕЗАПНО!) по рефакторингу. Как исправлять, поддерживать и покрывать тестами код, при этом сохраняя старый код и не рискуя ничего поломать. Далеко не со всеми методами лично я согласен, однако, есть и некоторые интересные приёмчики.
Коротко об основных приёмах:
1. Сохраняем сигнатуры
Даже самые ужасные на вид сигнатуры из легаси методов безопаснее просто скопировать для использования в новых методах, чем производить какие-либо манипуляции с аргументами.
2. Метод/класс росток
Если нужно внести дополнение в старый метод, вставляем туда новый метод, который покрываем тестами. Хотя бы новый код будет протестирован.
3. Метод/класс обёртка
Для добавления функциональности к старому методу создаём новый метод, в котором вызываем старый и добавляем новый код. В отношении классов используем шаблон Декоратор: наследуем от старого класса, добавляя функциональность.
4. Извлечение и переопределение
Если метод использует функциональность, которую нельзя или трудно протестировать явно (запись в консоль/файл/БД, отправка писем клиентам, отправка платежей и т.п.), извлекаем вызов каждого такого метода в новый метод, который делаем
protected virtual
. Далее создаём тестовый класс, унаследованный от старого класса, в котором переопределяем нужные методы, чтобы их можно было протестировать (например, вместо записи в файл сохраняем в память). Таким образом можно протестировать логику старого класса через тестовый, не вызывая ненужных нам методов.