День двести восемьдесят пятый. #BestPractices
Советы по использованию общих типов
Коллекции. Окончание
Выбор между массивами и коллекциями
✅ ИСПОЛЬЗУЙТЕ коллекции вместо массивов. Коллекции обеспечивают больший контроль над содержимым, могут расширяться с течением времени и более удобны в использовании. Кроме того, использование массивов для сценариев только для чтения не рекомендуется, поскольку стоимость клонирования массива непомерно высока. Также разработчикам удобнее пользоваться API на основе коллекций.
⚠️ РАССМОТРИТЕ использование массивов, если вы разрабатываете низкоуровневые API. Массивы занимают меньше места в памяти, что помогает уменьшить рабочий набор, а доступ к элементам в массиве быстрее, потому что он оптимизируется во время выполнения.
✅ ИСПОЛЬЗУЙТЕ массивы байтов вместо коллекций байтов.
❌ ИЗБЕГАЙТЕ использования массива для свойств, возвращающих новый массив (например, копию внутреннего массива) каждый раз, когда вызывается аксессор свойства.
Реализация пользовательских коллекций
⚠️ РАССМОТРИТЕ наследование от
✅ ИСПОЛЬЗУЙТЕ реализацию
⚠️ РАССМОТРИТЕ реализацию необобщённых интерфейсов коллекции (
❌ ИЗБЕГАЙТЕ реализации интерфейсов коллекций типами со сложными API, не связанными с концепцией коллекции.
❌ ИЗБЕГАЙТЕ наследования от необобщённых базовых коллекций, таких как
Именование пользовательских коллекций
Коллекции (типы, которые реализуют
1. Создания новой структуры данных со специфическими операциями и часто отличающимися характеристиками производительности от существующих структур данных (например,
2. Создания специализированной коллекции для хранения определенного набора элементов (например,
✅ ИСПОЛЬЗУЙТЕ суффикс «
✅ ИСПОЛЬЗУЙТЕ суффикс «
✅ ИСПОЛЬЗУЙТЕ подходящее имя структуры данных для пользовательских структур данных. Избегайте использования любых суффиксов, подразумевающих конкретную реализацию, таких как «
⚠️ РАССМОТРИТЕ использование префикса в виде имени элемента в имени коллекции. Например, коллекция, хранящая элементы типа
⚠️ РАССМОТРИТЕ использование префикса «
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
Советы по использованию общих типов
Коллекции. Окончание
Выбор между массивами и коллекциями
✅ ИСПОЛЬЗУЙТЕ коллекции вместо массивов. Коллекции обеспечивают больший контроль над содержимым, могут расширяться с течением времени и более удобны в использовании. Кроме того, использование массивов для сценариев только для чтения не рекомендуется, поскольку стоимость клонирования массива непомерно высока. Также разработчикам удобнее пользоваться API на основе коллекций.
⚠️ РАССМОТРИТЕ использование массивов, если вы разрабатываете низкоуровневые API. Массивы занимают меньше места в памяти, что помогает уменьшить рабочий набор, а доступ к элементам в массиве быстрее, потому что он оптимизируется во время выполнения.
✅ ИСПОЛЬЗУЙТЕ массивы байтов вместо коллекций байтов.
❌ ИЗБЕГАЙТЕ использования массива для свойств, возвращающих новый массив (например, копию внутреннего массива) каждый раз, когда вызывается аксессор свойства.
Реализация пользовательских коллекций
⚠️ РАССМОТРИТЕ наследование от
Collection<T>
, ReadOnlyCollection<T>
или KeyedCollection<TKey, TItem>
при разработке новых коллекций.✅ ИСПОЛЬЗУЙТЕ реализацию
IEnumerable<T>
при разработке новых коллекций. Попробуйте реализовать ICollection<T>
или даже IList<T>
там, где это имеет смысл. При реализации такой пользовательской коллекции следуйте шаблону API, установленному интерфейсами Collection<T>
и ReadOnlyCollection<T>
, как можно точнее. То есть, явно реализуйте те же члены, используйте те же имена параметров, что и эти две коллекции, и т.д.⚠️ РАССМОТРИТЕ реализацию необобщённых интерфейсов коллекции (
IList
и ICollection
), если коллекция часто будет передаваться API, принимающим данные в таком виде.❌ ИЗБЕГАЙТЕ реализации интерфейсов коллекций типами со сложными API, не связанными с концепцией коллекции.
❌ ИЗБЕГАЙТЕ наследования от необобщённых базовых коллекций, таких как
CollectionBase
. Вместо этого используйте Collection<T>
, ReadOnlyCollection<T>
и KeyedCollection<TKey, TItem>
.Именование пользовательских коллекций
Коллекции (типы, которые реализуют
IEnumerable
) в основном создаются для: 1. Создания новой структуры данных со специфическими операциями и часто отличающимися характеристиками производительности от существующих структур данных (например,
List<T>
, LinkedList<T>
, Queue<T>
).2. Создания специализированной коллекции для хранения определенного набора элементов (например,
StringCollection
). Структуры данных чаще всего используются во внутренней реализации приложений и библиотек. Специализированные коллекции в основном представлены в интерфейсе API (как типы свойств и параметров).✅ ИСПОЛЬЗУЙТЕ суффикс «
Dictionary
» в именах абстракций, реализующих IDictionary
или IDictionary<TKey, TValue>
.✅ ИСПОЛЬЗУЙТЕ суффикс «
Collection
» в именах типов, реализующих IEnumerable
(или любого из его потомков) и представляющих список элементов.✅ ИСПОЛЬЗУЙТЕ подходящее имя структуры данных для пользовательских структур данных. Избегайте использования любых суффиксов, подразумевающих конкретную реализацию, таких как «
LinkedList
» или «Hashtable
», в именах абстракций коллекции.⚠️ РАССМОТРИТЕ использование префикса в виде имени элемента в имени коллекции. Например, коллекция, хранящая элементы типа
Address
(реализующая IEnumerable<Address>
), должна называться AddressCollection
. Если коллекция содержи элементы интерфейсного типа, префикс «I
» может быть опущен. Таким образом, коллекция элементов типа IDisposable
может называться DisposableCollection
.⚠️ РАССМОТРИТЕ использование префикса «
ReadOnly
» в именах коллекций, доступных только для чтения, если соответствующая коллекция с возможностью записи может быть добавлена или уже существует в платформе. Например, коллекция строк только для чтения должна называться ReadOnlyStringCollection
.Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести восемьдесят шестой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
7. Осторожнее с повторным использованием
Это был мой первый проект в компании. Я только что закончил свою степень и очень хотел проявить себя, задерживаясь каждый день, просматривая существующий код. Работая над своей первой функцией, я приложил дополнительные усилия, чтобы внедрить всё, что я узнал: комментирование, ведение журнала, помещение общего кода в библиотеки, где это возможно, стиль и т.п. Однако обзор кода, к которому я чувствовал себя полностью готовым, стал ударом под дых от реальности: повторное использование было осуждено!
Как это могло произойти? На протяжении всего моего обучения повторное использование считалось воплощением качественной разработки программного обеспечения. Все статьи и учебники, которые я читал, опытные профессионалы, которые учили меня, - разве все меня обманывали?
Оказывается, я упустил одну критически важную вещь.
Контекст.
То, что две совершенно разные части системы выполняли некоторую логику одинаково, оказалось не таким важным, как мне казалось. До тех пор, пока я не вытащил этот общий код в библиотеки, эти части не зависели друг от друга. Каждая часть могла развиваться независимо. Каждая часть могла изменить свою логику в соответствии с потребностями меняющейся бизнес-среды системы. Эти четыре строки схожего кода были случайными. Временной аномалией, совпадением. Всё было хорошо, пока не пришёл я.
Библиотеки общего кода, которые я создал, привязали шнурки одной ноги к другой. Теперь изменения в одном бизнес-домене не могли быть выполнены без предварительной синхронизации с другим. Раньше затраты на обслуживание этих независимых функций были незначительными, но общая библиотека требовала на порядок более сложного тестирования.
Хотя я уменьшил абсолютное количество строк кода в системе, я увеличил количество зависимостей. Контекст этих зависимостей имеет решающее значение. Находись эти две функции в одном контексте, совместное использование кода могло бы быть оправданным и иметь некоторую ценность. Но когда зависимости не контролируются, их усики запутываются и приводят к большим проблемам в системе, хотя сам код выглядит отлично.
Эти ошибки коварны тем, что по своей сути они выглядят как хорошая идея. При применении в правильном контексте эти методы правильны и приносят пользу. В неправильном контексте они увеличивают цену, а не ценность. Теперь, когда я захожу в существующую кодовую базу, не зная, где будут использоваться различные её части, я гораздо более осторожен в отношении повторного использования кода.
Будьте осторожны с повторным использованием кода. Сначала проанализируйте контекст и только потом приступайте к реализации.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала - Udi Dahan
97 Вещей, Которые Должен Знать Каждый Программист
7. Осторожнее с повторным использованием
Это был мой первый проект в компании. Я только что закончил свою степень и очень хотел проявить себя, задерживаясь каждый день, просматривая существующий код. Работая над своей первой функцией, я приложил дополнительные усилия, чтобы внедрить всё, что я узнал: комментирование, ведение журнала, помещение общего кода в библиотеки, где это возможно, стиль и т.п. Однако обзор кода, к которому я чувствовал себя полностью готовым, стал ударом под дых от реальности: повторное использование было осуждено!
Как это могло произойти? На протяжении всего моего обучения повторное использование считалось воплощением качественной разработки программного обеспечения. Все статьи и учебники, которые я читал, опытные профессионалы, которые учили меня, - разве все меня обманывали?
Оказывается, я упустил одну критически важную вещь.
Контекст.
То, что две совершенно разные части системы выполняли некоторую логику одинаково, оказалось не таким важным, как мне казалось. До тех пор, пока я не вытащил этот общий код в библиотеки, эти части не зависели друг от друга. Каждая часть могла развиваться независимо. Каждая часть могла изменить свою логику в соответствии с потребностями меняющейся бизнес-среды системы. Эти четыре строки схожего кода были случайными. Временной аномалией, совпадением. Всё было хорошо, пока не пришёл я.
Библиотеки общего кода, которые я создал, привязали шнурки одной ноги к другой. Теперь изменения в одном бизнес-домене не могли быть выполнены без предварительной синхронизации с другим. Раньше затраты на обслуживание этих независимых функций были незначительными, но общая библиотека требовала на порядок более сложного тестирования.
Хотя я уменьшил абсолютное количество строк кода в системе, я увеличил количество зависимостей. Контекст этих зависимостей имеет решающее значение. Находись эти две функции в одном контексте, совместное использование кода могло бы быть оправданным и иметь некоторую ценность. Но когда зависимости не контролируются, их усики запутываются и приводят к большим проблемам в системе, хотя сам код выглядит отлично.
Эти ошибки коварны тем, что по своей сути они выглядят как хорошая идея. При применении в правильном контексте эти методы правильны и приносят пользу. В неправильном контексте они увеличивают цену, а не ценность. Теперь, когда я захожу в существующую кодовую базу, не зная, где будут использоваться различные её части, я гораздо более осторожен в отношении повторного использования кода.
Будьте осторожны с повторным использованием кода. Сначала проанализируйте контекст и только потом приступайте к реализации.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала - Udi Dahan
День двести восемьдесят седьмой. #ЗаметкиНаПолях
Больше возможностей передачи по ссылке. Начало
В C#7 добавлены несколько новых возможностей использования значимых переменных по ссылке.
Локальные ref-переменные
Локальные ref-переменные позволяют вам объявить новую локальную переменную, которая использует тот же адрес в памяти, что и существующая переменная. В следующем примере мы дважды инкрементируем одно и то же значение через различные переменные. Обратите внимание, что на использование ключевого слова
Любое выражение соответствующего типа, которое классифицируется как переменная, может использоваться для инициализации локальной ref-переменной, включая элементы массива. Если у вас есть массив больших изменяемых значимых типов, это поможет избежать ненужных операций копирования для внесения нескольких изменений. Также локальные ref-переменные можно использовать с полями объекта.
ПРИМЕЧАНИЕ: Локальная ref-переменная предотвратит уничтожение объекта сборщиком мусора до последнего использования этой переменной. Точно так же использование ref-переменной для элемента массива предотвращает уничтожение массива, содержащего этот элемент. Ref-переменная, которая ссылается на поле внутри объекта или элемент массива, усложняет жизнь сборщику мусора. Он должен определить, к какому объекту относится переменная, и поддерживать этот объект живым. Обычные ссылки на объекты проще, потому что они напрямую идентифицируют вовлеченный объект. Каждая ref-переменная, которая ссылается на поле в объекте, вводит указатель на внутреннюю структуру данных в объекте, поддерживаемом сборщиком мусора. Было бы накладно иметь много таких указателей одновременно, но ref-переменные могут появляться только в стеке, что снижает вероятность того, что их будет столько, чтобы вызвать проблемы с производительностью.
Возвращаемые ref-переменные
Вот простейший пример использования возвращаемых ref-переменных: метод
- Локальные переменные, объявленные в методе (включая значения параметров)
- Поля структур, объявленных в методе
В дополнение к этим ограничениям
Тернарный оператор может использовать значения ref для второго и третьего операндов, и в этом случае результат оператора также является переменной, которую можно использовать с модификатором
Продолжение следует...
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
Больше возможностей передачи по ссылке. Начало
В C#7 добавлены несколько новых возможностей использования значимых переменных по ссылке.
Локальные ref-переменные
Локальные ref-переменные позволяют вам объявить новую локальную переменную, которая использует тот же адрес в памяти, что и существующая переменная. В следующем примере мы дважды инкрементируем одно и то же значение через различные переменные. Обратите внимание, что на использование ключевого слова
ref
как в объявлении, так и в инициализаторе.int x = 10;В результате получается 12, как если бы мы увеличили
ref int y = ref x;
x++;
y++;
Console.WriteLine(x);
х
дважды.Любое выражение соответствующего типа, которое классифицируется как переменная, может использоваться для инициализации локальной ref-переменной, включая элементы массива. Если у вас есть массив больших изменяемых значимых типов, это поможет избежать ненужных операций копирования для внесения нескольких изменений. Также локальные ref-переменные можно использовать с полями объекта.
ПРИМЕЧАНИЕ: Локальная ref-переменная предотвратит уничтожение объекта сборщиком мусора до последнего использования этой переменной. Точно так же использование ref-переменной для элемента массива предотвращает уничтожение массива, содержащего этот элемент. Ref-переменная, которая ссылается на поле внутри объекта или элемент массива, усложняет жизнь сборщику мусора. Он должен определить, к какому объекту относится переменная, и поддерживать этот объект живым. Обычные ссылки на объекты проще, потому что они напрямую идентифицируют вовлеченный объект. Каждая ref-переменная, которая ссылается на поле в объекте, вводит указатель на внутреннюю структуру данных в объекте, поддерживаемом сборщиком мусора. Было бы накладно иметь много таких указателей одновременно, но ref-переменные могут появляться только в стеке, что снижает вероятность того, что их будет столько, чтобы вызвать проблемы с производительностью.
Возвращаемые ref-переменные
Вот простейший пример использования возвращаемых ref-переменных: метод
RefReturn
возвращает любую переменную, которая была передана в него.static void Main()Получается 11, потому что
{
int x = 10;
ref int y = ref RefReturn(ref x);
y++;
Console.WriteLine(x);
}
static ref int RefReturn(ref int p)
{
return ref p;
}
x
и y
находятся в по одному адресу в памяти, так же, как если бы вы написалиref int y = ref x;Метод не может возвращать ссылку на адрес в памяти, которую он создаёт сам, потому что, когда стек метода удаляется после возвращения из метода, этот адрес больше не будет действительным. Таким образом, не могут быть возвращены с помощью
ref return
:- Локальные переменные, объявленные в методе (включая значения параметров)
- Поля структур, объявленных в методе
В дополнение к этим ограничениям
ref return
недопустим в асинхронных методах и блоках итераторов. Подобно указателям, вы не можете использовать модификатор ref
в аргументе типа, хотя он может появляться в объявлениях интерфейса и делегатах:delegate ref int RefFuncInt32();Ref-переменные и тернарный оператор (C# 7.2)
Тернарный оператор может использовать значения ref для второго и третьего операндов, и в этом случае результат оператора также является переменной, которую можно использовать с модификатором
ref
. В качестве примера в следующем листинге показан метод, который считает чётные и нечётные значения в коллекции, возвращая результат в виде кортежа:static (int even, int odd) CountEvenAndOdd(IEnumerable<int> values)Код в зависимости от условия назначает ref-переменной
{
var result = (even: 0, odd: 0);
foreach (var value in values)
{
ref int counter = ref (value & 1) == 0 ?
ref result.even : ref result.odd;
counter++;
}
return result;
}
counter
ссылку либо на первый, либо на второй элемент кортежа, а затем увеличивает значение.Продолжение следует...
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
День двести восемьдесят восьмой. #ЗаметкиНаПолях
Больше возможностей передачи по ссылке. Продолжение
Ref readonly (C#7.2)
В C#7.2 появились ref-переменные только для чтения. Это может быть полезно в двух сценариях:
- создать псевдоним для поля только для чтения, чтобы избежать копирования.
- разрешить доступ только для чтения через ref-переменную.
И локальные, и возвращаемые ref-переменные быть объявлены с модификатором
Заметьте, что, если вы вызываете метод или индексатор, возвращающий
Модификатор
Продолжение следует...
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
Больше возможностей передачи по ссылке. Продолжение
Ref readonly (C#7.2)
В C#7.2 появились ref-переменные только для чтения. Это может быть полезно в двух сценариях:
- создать псевдоним для поля только для чтения, чтобы избежать копирования.
- разрешить доступ только для чтения через ref-переменную.
И локальные, и возвращаемые ref-переменные быть объявлены с модификатором
readonly
. Результат доступен только для чтения, как readonly
поле. Вы не можете присвоить новое значение переменной, а если это структура, вы не можете изменять её поля или вызывать мутаторы свойств.Заметьте, что, если вы вызываете метод или индексатор, возвращающий
ref readonly
в локальную переменную, то и эта переменная должна быть объявлена как ref readonly
:// readonly полеЭто находит интересное применение в индексаторах. Например, можно создать представление «только для чтения» для коллекции аналогично
static readonly int field = DateTime.UtcNow.Second;
// возвращает readonly псевдоним для поля
static ref readonly int GetFieldAlias() => ref field;
static void Main()
{
// инициализация локальной ref-переменной только для чтения
ref readonly int local = ref GetFieldAlias();
Console.WriteLine(local);
}
ReadOnlyCollection
, но без копирования элементов:class ReadOnlyArrayView<T>…
{
private readonly T[] values;
// конструктор копирует ссылку на массив
// без копирования элементов
public ReadOnlyArrayView(T[] values) =>
this.values = values;
// ref-индексатор только для чтения
// предоставляет ссылку на элемент коллекции
public ref readonly T this[int index] =>
ref values[index];
}
static void Main()Этот пример не особо убедителен с точки зрения повышения производительности, поскольку int небольшой тип. Но в сценариях, использующих крупные структуры в качестве элементов коллекции, экономия в выделении памяти и частоте сбора мусора может быть значительной.
{
// исходный изменяемый массив array
var array = new int[] { 10, 20, 30 };
// представление только для чтения view
var view = new ReadOnlyArrayView<int>(array);
ref readonly int element = ref view[0];
Console.WriteLine(element);
// можно изменять сам массив через array, но не через view
// изменения в массиве «видны» в представлении
array[0] = 100;
Console.WriteLine(element);
}
Модификатор
readonly
может применяться к локальным и возвращаемым ref-переменным, а как насчёт параметров? Об этом в следующем посте.Продолжение следует...
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
День двести восемьдесят девятый. #Оффтоп
Продолжаю тему «ютуб подкинул в рекоммендациях».
Если вы программист, но не знаете, кто такой Дядя Боб, то самое время с ним познакомиться, потому
что велик шанс, что дядя уже программировал ещё до того, как родились ваши родители.
Как зародилось программирование? Сколько времени занимал процесс компиляции кода в 50-х? Как бы
выглядел ламповый айфон? Как появился Agile? Куда, чёрт возьми, делись женщины-программисты? До
чего мы дошли и куда катится программистский мир?
Обо всём этом и о многом другом с шутками, прибаутками и профессиональными байками рассказывает сам
мэтр. Так что, если у вас есть полтора часа свободного времени, очень рекомендую.
Кстати несмотря на то, что C# в видео не упоминается, книжка по шарпам у дяди Боба тоже есть шьгл
в помощь).
Ну и… да, стоит ли в который раз напоминать, что всё самое интересное в программировании на
английском https://youtu.be/ecIWPzGEbFc
Продолжаю тему «ютуб подкинул в рекоммендациях».
Если вы программист, но не знаете, кто такой Дядя Боб, то самое время с ним познакомиться, потому
что велик шанс, что дядя уже программировал ещё до того, как родились ваши родители.
Как зародилось программирование? Сколько времени занимал процесс компиляции кода в 50-х? Как бы
выглядел ламповый айфон? Как появился Agile? Куда, чёрт возьми, делись женщины-программисты? До
чего мы дошли и куда катится программистский мир?
Обо всём этом и о многом другом с шутками, прибаутками и профессиональными байками рассказывает сам
мэтр. Так что, если у вас есть полтора часа свободного времени, очень рекомендую.
Кстати несмотря на то, что C# в видео не упоминается, книжка по шарпам у дяди Боба тоже есть шьгл
в помощь).
Ну и… да, стоит ли в который раз напоминать, что всё самое интересное в программировании на
английском https://youtu.be/ecIWPzGEbFc
YouTube
"Uncle" Bob Martin - "The Future of Programming"
How did our industry start, what paths did it take to get to where we are, and where is it going. What big problems did programmers encounter in the past? How were they solved? And how do those solutions impact our future? What mistakes have we made as a…
День двести девяностый. #ЗаметкиНаПолях
Больше возможностей передачи по ссылке. Продолжение
In-параметры (C# 7.2)
В C#7.2 добавлен новый модификатор параметров
Разница между параметром
Перегрузка in-параметров
Правила те же, что и для
Тогда перегрузка будет использоваться только при вызове с явным указанием in-параметра.
Советы по применению
Во-первых, in-параметры предназначены для повышения производительности. Как правило, не стоит вносить какие-либо изменения в ваш код для повышения производительности, пока вы не измерили производительность очевидным и повторяемым способом и не убедились, что изменения достигают вашей цели.
Основная проблема с in-параметрами в том, что они могут значительно усложнить анализ вашего кода. Вы можете прочитать значение одного и того же параметра дважды и получить разные результаты несмотря на то, что ваш метод ничего не изменял. Это усложняет написание правильного кода и упрощает написание кода, который только кажется правильным.
✅ Используйте in-параметры только тогда, когда есть ощутимый и значительный выигрыш в производительности. Это наиболее вероятно, когда задействованы большие структуры.
❌ Избегайте использования in-параметров в общедоступных API.
⚠️ Рассмотрите возможность использования открытого метода в качестве барьера против изменений, а затем используйте in-параметры в закрытом методе, чтобы избежать копирования.
⚠️ Рассмотрите возможность явного использования модификатора in при вызове метода, который принимает in-параметр. Это лишний раз сообщит о ваших намерениях.
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
Больше возможностей передачи по ссылке. Продолжение
In-параметры (C# 7.2)
В C#7.2 добавлен новый модификатор параметров
in
, похожий на ref
или out
. Когда параметр имеет модификатор in
, предполагается, что метод не будет изменять значения параметра, поэтому переменная может быть передана по ссылке, чтобы избежать копирования. Внутри метода параметр in
действует как локальная ref readonly
переменная.Разница между параметром
in
и параметром ref
или out
в том, что вызывающей стороне не нужно указывать модификатор in
для аргумента. Если модификатор in
отсутствует, компилятор передаст аргумент по ссылке, если передана переменная, или скопирует значение в скрытую локальную переменную, которую передаст по ссылке. Если вызывающая сторона указывает модификатор in
явно, вызов будет действителен, только если аргумент может быть передан по ссылке напрямую:static void PrintDateTime(in DateTime value)Может показаться, что, если вы не изменяете параметр в методе, можно сделать его in-параметром. Но это опасное предположение. Компилятор останавливает метод от изменения параметра, но он ничего не может сделать с другим кодом, изменяющим его. Вы должны помнить, что параметр
{
string text = value.ToString(
"yyyy-MM-dd'T'HH:mm:ss",
CultureInfo.InvariantCulture);
Console.WriteLine(text);
}
static void Main()
{
DateTime start = DateTime.UtcNow;
//неявная передача по ссылке
PrintDateTime(start);
//явная передача по ссылке
PrintDateTime(in start);
//значение копируется в скрытую переменную
PrintDateTime(start.AddMinutes(1));
//ошибка компиляции:
//значение не может явно передаваться по ссылке
PrintDateTime(in start.AddMinutes(1));
}
in
является псевдонимом для адреса хранения значения, которое может изменить другой код. Например, параметр in
может оказаться псевдонимом для поля в том же классе. В этом случае любые изменения в поле (в самом методе или в другом коде) будут видны через in-параметр. Но из кода это не очевидно ни в вызывающем коде, ни в самом методе. Еще сложнее предсказать, что произойдёт, если задействовано несколько потоков.Перегрузка in-параметров
Правила те же, что и для
ref
и out
параметров. Нельзя использовать перегрузки, отличающиеся только модификатором ref
/out
/in
. Но вы можете перегрузить метод с обычным параметром методом с in-параметром:void Method(int x) { ... }
void Method(in int x) { ... }
Тогда перегрузка будет использоваться только при вызове с явным указанием in-параметра.
Советы по применению
Во-первых, in-параметры предназначены для повышения производительности. Как правило, не стоит вносить какие-либо изменения в ваш код для повышения производительности, пока вы не измерили производительность очевидным и повторяемым способом и не убедились, что изменения достигают вашей цели.
Основная проблема с in-параметрами в том, что они могут значительно усложнить анализ вашего кода. Вы можете прочитать значение одного и того же параметра дважды и получить разные результаты несмотря на то, что ваш метод ничего не изменял. Это усложняет написание правильного кода и упрощает написание кода, который только кажется правильным.
✅ Используйте in-параметры только тогда, когда есть ощутимый и значительный выигрыш в производительности. Это наиболее вероятно, когда задействованы большие структуры.
❌ Избегайте использования in-параметров в общедоступных API.
⚠️ Рассмотрите возможность использования открытого метода в качестве барьера против изменений, а затем используйте in-параметры в закрытом методе, чтобы избежать копирования.
⚠️ Рассмотрите возможность явного использования модификатора in при вызове метода, который принимает in-параметр. Это лишний раз сообщит о ваших намерениях.
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
День двести девяносто первый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
8. Правило Бойскаута
У бойскаутов есть правило: «Всегда оставляй место стоянки чище, чем оно было до тебя». Если стоянка загажена, вы её очищаете независимо от того, кто её загадил. Вы намеренно улучшаете окружающую среду для следующей группы отдыхающих. (На самом деле, в оригинале это правило, написанное отцом движения скаутов Робертом Стивенсоном Смитом Баден-Пауэлом, звучит так: «Старайтесь оставить этот мир чуть лучше, чем он был до вашего прихода».)
Что если бы мы следовали аналогичному правилу в нашем коде: «Всегда оставляйте код чище, чем он был, когда вы его проверяли»? Независимо от того, кто его автор, что, если мы всегда прилагали бы некоторые усилия, даже самые минимальные, чтобы улучшить код? Какой был бы результат?
Я думаю, что, если бы мы все следовали этому простому правилу, мы бы увидели конец неумолимого ухудшения наших программных систем. Вместо этого наши системы постепенно становились бы всё лучше и лучше по мере их развития. А команды заботились бы о системе в целом, а не каждый член о своей маленькой части.
Я не думаю, что это правило слишком трудное для выполнения. Вам не нужно доводить каждый блок программы до совершенства при каждой проверке. Просто нужно сделать его немного лучше. Конечно, это означает, что любой код, который вы добавляете, должен быть чистым. Это также означает, что перед повторной проверкой блока вы улучшите ещё хоть что-нибудь. Вы можете просто переименовать плохо названную переменную или разбить одну длинную функцию на две маленькие, разорвать циклическую зависимость или добавить интерфейс для отделения публичного API от деталей реализации.
Честно говоря, для меня это звучит как обычное правило этикета, как, например, мыть руки после посещения туалета или бросать мусор в урну, а не на пол. Действительно, оставить беспорядок в коде должно быть столь же социально неприемлемым, как мусорить. Это должно быть что-то, чего просто нельзя делать.
Но в этом есть нечто большее. Забота о нашем собственном коде - это одно. Забота о коде команды - совсем другое. Команды помогают друг другу и убирают друг за другом. Они следуют правилу бойскаутов, потому что это хорошо для всех, а не только для них.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Роберт Мартин (Дядя Боб)
97 Вещей, Которые Должен Знать Каждый Программист
8. Правило Бойскаута
У бойскаутов есть правило: «Всегда оставляй место стоянки чище, чем оно было до тебя». Если стоянка загажена, вы её очищаете независимо от того, кто её загадил. Вы намеренно улучшаете окружающую среду для следующей группы отдыхающих. (На самом деле, в оригинале это правило, написанное отцом движения скаутов Робертом Стивенсоном Смитом Баден-Пауэлом, звучит так: «Старайтесь оставить этот мир чуть лучше, чем он был до вашего прихода».)
Что если бы мы следовали аналогичному правилу в нашем коде: «Всегда оставляйте код чище, чем он был, когда вы его проверяли»? Независимо от того, кто его автор, что, если мы всегда прилагали бы некоторые усилия, даже самые минимальные, чтобы улучшить код? Какой был бы результат?
Я думаю, что, если бы мы все следовали этому простому правилу, мы бы увидели конец неумолимого ухудшения наших программных систем. Вместо этого наши системы постепенно становились бы всё лучше и лучше по мере их развития. А команды заботились бы о системе в целом, а не каждый член о своей маленькой части.
Я не думаю, что это правило слишком трудное для выполнения. Вам не нужно доводить каждый блок программы до совершенства при каждой проверке. Просто нужно сделать его немного лучше. Конечно, это означает, что любой код, который вы добавляете, должен быть чистым. Это также означает, что перед повторной проверкой блока вы улучшите ещё хоть что-нибудь. Вы можете просто переименовать плохо названную переменную или разбить одну длинную функцию на две маленькие, разорвать циклическую зависимость или добавить интерфейс для отделения публичного API от деталей реализации.
Честно говоря, для меня это звучит как обычное правило этикета, как, например, мыть руки после посещения туалета или бросать мусор в урну, а не на пол. Действительно, оставить беспорядок в коде должно быть столь же социально неприемлемым, как мусорить. Это должно быть что-то, чего просто нельзя делать.
Но в этом есть нечто большее. Забота о нашем собственном коде - это одно. Забота о коде команды - совсем другое. Команды помогают друг другу и убирают друг за другом. Они следуют правилу бойскаутов, потому что это хорошо для всех, а не только для них.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Роберт Мартин (Дядя Боб)
День двести девяносто второй.
Сертификат Microsoft. Экзамен 70-486. Шаг первый
Итак, как я уже писал выше, я нацелился на сертификат «Microsoft® Certified Solutions Associate: Web Applications». Таким образом, мне нужно сдать ещё один экзамен «Developing ASP.NET MVC Web Applications».
Что можно сказать при беглом осмотре описания:
1. Список тем кажется гораздо обширнее, чем по языку C# (хотя и там было не мало).
2. Похоже, нужно изучить как Framework, так и Core, более того знать отличия.
3. Какое-то нереальное количество вопросов по Azure.
4. В отличие от языка C#, источников информации крайне мало. По крайней мере, из того, что мне удалось найти, три с половиной книги по ASP.NET MVC и пара видеокурсов на Pluralsight (с платной подпиской) по Azure. Это, конечно, не считая предлагаемых очных 5-дневных (sic!!!) курсов за 30-40 т.р. Чему там за 5 дней могут научить, решительно непонятно. Судя по программе курса на одном из сайтов, они там просто идут по книге Адама Фримена «ASP.NET MVC с примерами на C#», что составляет процентов 20 от списка тем экзамена.
В общем, пока перспективы не сильно радужные, подбираю книги по MVC, с Azure буду разбираться потом.
UPD: Немного покопавшись на сайте MSDN Channel 9, где был видеокурс для подготовки к экзамену по C#, нашёл аналогичный курс по ASP.NET MVC.
Сертификат Microsoft. Экзамен 70-486. Шаг первый
Итак, как я уже писал выше, я нацелился на сертификат «Microsoft® Certified Solutions Associate: Web Applications». Таким образом, мне нужно сдать ещё один экзамен «Developing ASP.NET MVC Web Applications».
Что можно сказать при беглом осмотре описания:
1. Список тем кажется гораздо обширнее, чем по языку C# (хотя и там было не мало).
2. Похоже, нужно изучить как Framework, так и Core, более того знать отличия.
3. Какое-то нереальное количество вопросов по Azure.
4. В отличие от языка C#, источников информации крайне мало. По крайней мере, из того, что мне удалось найти, три с половиной книги по ASP.NET MVC и пара видеокурсов на Pluralsight (с платной подпиской) по Azure. Это, конечно, не считая предлагаемых очных 5-дневных (sic!!!) курсов за 30-40 т.р. Чему там за 5 дней могут научить, решительно непонятно. Судя по программе курса на одном из сайтов, они там просто идут по книге Адама Фримена «ASP.NET MVC с примерами на C#», что составляет процентов 20 от списка тем экзамена.
В общем, пока перспективы не сильно радужные, подбираю книги по MVC, с Azure буду разбираться потом.
UPD: Немного покопавшись на сайте MSDN Channel 9, где был видеокурс для подготовки к экзамену по C#, нашёл аналогичный курс по ASP.NET MVC.
День двести девяносто третий. #ЗаметкиНаПолях
Объявление структур только для чтения (C#7.2)
C# долгое время неявно копировал структуры. Все это задокументировано в спецификации. Причина, по которой компилятор делает эту копию, состоит в том, чтобы избежать изменения поля, доступного только для чтения, кодом в свойстве (или методом, если вы его вызываете). Смысл поля только для чтения состоит в том, что ничто не может изменить его значение. Было бы странно, если бы
Но что, если структура может пообещать, что она этого не сделает? В конце концов, большинство структур разработано, чтобы быть неизменяемыми. В C#7.2 вы можете применить модификатор readonly к объявлению структуры, чтобы это сделать:
1. Каждое поле и автоматически реализованное свойство экземпляра должны быть доступны только для чтения. Статические поля и свойства все ещё могут быть доступны для чтения и записи.
2. Вы можете обращаться к
- как out-параметр в конструкторах (инициализирует поле);
- как ref-параметр в членах обычных структур (изменяет значение поля по ссылке);
- как in-параметр в членах структур только для чтения (читает значение поля по ссылке).
Там, где вы можете сделать свои пользовательские структуры доступными только для чтения, я призываю вас сделать это. Просто помните, что это одностороннее изменение для публичного кода. Вы можете безопасно удалить модификатор позже, только если у вас есть возможность перекомпилировать весь код, который использует эту структуру.
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
Объявление структур только для чтения (C#7.2)
C# долгое время неявно копировал структуры. Все это задокументировано в спецификации. Причина, по которой компилятор делает эту копию, состоит в том, чтобы избежать изменения поля, доступного только для чтения, кодом в свойстве (или методом, если вы его вызываете). Смысл поля только для чтения состоит в том, что ничто не может изменить его значение. Было бы странно, если бы
readOnlyField.SomeMethod()
мог изменять поле. C# рассчитан на то, что любые мутаторы (set
) свойств будут изменять данные, поэтому они запрещены для полей только для чтения. Но даже аксессор (get
) свойства может попытаться изменить значение. Поэтому скрытая копия - это эффективная мера безопасности.Но что, если структура может пообещать, что она этого не сделает? В конце концов, большинство структур разработано, чтобы быть неизменяемыми. В C#7.2 вы можете применить модификатор readonly к объявлению структуры, чтобы это сделать:
public readonly struct YearMonthDayВы можете применять модификатор только в том случае, если ваша структура действительно доступна только для чтения и поэтому соответствует следующим условиям:
{
public int Year { get; }
public int Month { get; }
public int Day { get; }
public YearMonthDay(int year, int month, int day) =>
(Year, Month, Day) = (year, month, day);
}
1. Каждое поле и автоматически реализованное свойство экземпляра должны быть доступны только для чтения. Статические поля и свойства все ещё могут быть доступны для чтения и записи.
2. Вы можете обращаться к
this
только внутри конструкторов. Можно рассматривать this
в структурах:- как out-параметр в конструкторах (инициализирует поле);
- как ref-параметр в членах обычных структур (изменяет значение поля по ссылке);
- как in-параметр в членах структур только для чтения (читает значение поля по ссылке).
Там, где вы можете сделать свои пользовательские структуры доступными только для чтения, я призываю вас сделать это. Просто помните, что это одностороннее изменение для публичного кода. Вы можете безопасно удалить модификатор позже, только если у вас есть возможность перекомпилировать весь код, который использует эту структуру.
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
День двести девяносто четвёртый. #ЗаметкиНаПолях
Больше возможностей передачи по ссылке. Продолжение
Методы расширения с ref или in параметрами (C#7.2)
Предположим, у вас есть большая структура, которую вы не хотите копировать, и метод, который вычисляет результат на основе значений свойств этой структуры (например, длину трехмерного вектора). Хорошо, если структура предоставляет сам метод (или свойство), особенно когда она объявлена с модификатором readonly. Вы можете избежать копирования без проблем. Но, возможно, вы делаете что-то более сложное, что авторы структуры не предусмотрели. Рассмотрим структуру
В C#7.2 вы можете написать методы расширения с модификатором
Использовать методы расширения просто. Единственный, возможно, удивительный аспект заключается в том, что в отличие от обычных параметров
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
Больше возможностей передачи по ссылке. Продолжение
Методы расширения с ref или in параметрами (C#7.2)
Предположим, у вас есть большая структура, которую вы не хотите копировать, и метод, который вычисляет результат на основе значений свойств этой структуры (например, длину трехмерного вектора). Хорошо, если структура предоставляет сам метод (или свойство), особенно когда она объявлена с модификатором readonly. Вы можете избежать копирования без проблем. Но, возможно, вы делаете что-то более сложное, что авторы структуры не предусмотрели. Рассмотрим структуру
Vector3D
только для чтения со свойствами X
, Y
и Z
:public readonly struct Vector3DМожно написать метод, принимающий структуру с параметром
{
public double X { get; }
public double Y { get; }
public double Z { get; }
public Vector3D(double x, double y, double z)
{ X = x; Y = y; Z = z; }
}
in
, но это будет выглядеть не слишком красиво:double magnitude = VectorUtilities.Magnitude(vector);Есть методы расширения, но обычный метод расширения, подобный этому, будет копировать вектор при каждом вызове:
public static double Magnitude(this Vector3D vector)Неприятно выбирать между производительностью и удобочитаемостью.
В C#7.2 вы можете написать методы расширения с модификатором
ref
или in
для первого параметра. Модификатор может идти до или после this
. Если выполняется только чтение значений, используйте in
, если значения изменяются, то ref
:public static double Magnitude(this in Vector3D vec) =>Заметьте, что второй параметр в методе
Math.Sqrt(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z);
public static void OffsetBy(this ref Vector3D orig, in Vector3D off) =>
orig = new Vector3D(orig.X + off.X, orig.Y + off.Y, orig.Z + off.Z);
OffsetBy
является параметром in
. Мы максимально пытаемся избежать копирования.Использовать методы расширения просто. Единственный, возможно, удивительный аспект заключается в том, что в отличие от обычных параметров
ref
, при вызове методов расширения с такими параметрами о них нет никакого упоминания:var vector = new Vector3D(1.5, 2.0, 3.0);Вывод:
var offset = new Vector3D(5.0, 2.5, -1.0);
vector.OffsetBy(offset);
Console.WriteLine($"({vector.X}, {vector.Y}, {vector.Z})");
Console.WriteLine(vector.Magnitude());
(6.5, 4.5, 2)Вызов
8.15475321515004
OffsetBy
изменил переменную vector
, как и предполагалось. Таким образом, метод OffsetBy
делает нашу неизменяемую структуру Vector3D
в некотором роде изменяемой. Этот функционал новый и лучших практик использования ещё не выведено, поэтому параметры ref
пока стоит использовать с осторожностью.Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
This media is not supported in your browser
VIEW IN TELEGRAM
День двести девяносто пятый. #Оффтоп #МоиИнструменты
Object Exporter
В рабочем проекте логгер ошибок выкладывает сериализованные в JSON объекты в лог при возникновении ошибок. Возникла потребность сравнить состояние объекта из лога и состояние объекта в точке останова при дебаге. Начал копаться и нашёл расширение Object Exporter для Visual Studio. Он позволяет экспортировать объекты во время дебага и сериализовать их в код C# или в JSON или XML.
Варианты использования:
- Как описано выше, сравнение состояния объекта при дебаге.
- Поиск информации внутри объекта.
- Генерация инициализаторов объектов для юнит-тестов (сериализация в C#).
Судя по отзывам, есть несколько мелких косяков: давно не было обновлений, относительно медленная работа и (с чем я сам столкнулся) при экспорте в JSON вложенные объекты почему-то экспортируются без имени. Но ничего лучше я не нашёл. Если есть другие варианты, буду рад услышать предложения в чате
Object Exporter
В рабочем проекте логгер ошибок выкладывает сериализованные в JSON объекты в лог при возникновении ошибок. Возникла потребность сравнить состояние объекта из лога и состояние объекта в точке останова при дебаге. Начал копаться и нашёл расширение Object Exporter для Visual Studio. Он позволяет экспортировать объекты во время дебага и сериализовать их в код C# или в JSON или XML.
Варианты использования:
- Как описано выше, сравнение состояния объекта при дебаге.
- Поиск информации внутри объекта.
- Генерация инициализаторов объектов для юнит-тестов (сериализация в C#).
Судя по отзывам, есть несколько мелких косяков: давно не было обновлений, относительно медленная работа и (с чем я сам столкнулся) при экспорте в JSON вложенные объекты почему-то экспортируются без имени. Но ничего лучше я не нашёл. Если есть другие варианты, буду рад услышать предложения в чате
День двести девяносто шестой. #BestPractices
Советы по сериализации. Начало
Сериализация - это процесс преобразования объекта в формат, который можно легко сохранить или перенести. Например, вы можете сериализовать объект, передать его через Интернет с помощью HTTP и десериализовать его на конечном компьютере. Подробнее о процессе сериализации можно почитать тут.
Различают три основных типа сериализации:
- Data Contract
- XML
- Времени выполнения (бинарная или SOAP)
⚠️ РАССМОТРИТЕ возможность сериализации при разработке новых типов.
Выбор правильной технологии сериализации
⚠️ РАССМОТРИТЕ поддержку сериализации Data Contract, если экземпляры вашего типа, возможно, потребуется сохранять или использовать в веб-сервисах.
⚠️ РАССМОТРИТЕ поддержку сериализации XML вместо или в дополнение к Data Contract, если вам нужен больший контроль над форматом XML, который создается при сериализации типа. Это может быть необходимо в некоторых сценариях взаимодействия, где необходимо использовать конструкции XML, которые не поддерживаются сериализацией Data Contract, например, для создания атрибутов XML.
⚠️ РАССМОТРИТЕ поддержку сериализации времени выполнения, если экземпляры вашего типа должны перемещаться через границы .NET Remoting.
Поддержка сериализации Data Contract
Типы могут поддерживать сериализацию Data Contract, применяя атрибуты
⚠️ РАССМОТРИТЕ возможность сделать члены вашего типа открытыми, если тип может использоваться в средах с частичным доверием. В среде с полным доверием сериализаторы Data Contract могут сериализовать и десериализовать непубличные типы и члены.
❗️ НЕОБХОДИМО использовать и аксессор (get), и мутатор (set) для всех свойств, имеющих атрибут
⚠️ РАССМОТРИТЕ использование обратных вызовов сериализации для инициализации десериализованных экземпляров. За редкими исключениями, при десериализации объектов конструкторы не вызываются. Следовательно, любая логика, которая выполняется во время обычного создания объекта, должна быть реализована в методе обратного вызова. Методы обратного вызова помечаются атрибутами
⚠️ РАССМОТРИТЕ использование атрибута
❗️ НЕОБХОДИМО учитывать обратную и прямую совместимость при создании или изменении сериализуемых типов. Помните, что сериализованные потоки новых версий вашего типа могут быть десериализованы в старую версию типа, и наоборот. Учтите, что члены данных, даже закрытые и внутренние, не могут изменять свои имена, типы или даже порядок в новых версиях типа, если не будут приняты особые меры для сохранения контракта с использованием явных параметров атрибутов Data Contract. Проверьте совместимость сериализации при внесении изменений в сериализуемые типы. Попробуйте десериализовать новую версию в старую и наоборот.
⚠️ РАССМОТРИТЕ реализацию
Продолжение следует…
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
Советы по сериализации. Начало
Сериализация - это процесс преобразования объекта в формат, который можно легко сохранить или перенести. Например, вы можете сериализовать объект, передать его через Интернет с помощью HTTP и десериализовать его на конечном компьютере. Подробнее о процессе сериализации можно почитать тут.
Различают три основных типа сериализации:
- Data Contract
- XML
- Времени выполнения (бинарная или SOAP)
⚠️ РАССМОТРИТЕ возможность сериализации при разработке новых типов.
Выбор правильной технологии сериализации
⚠️ РАССМОТРИТЕ поддержку сериализации Data Contract, если экземпляры вашего типа, возможно, потребуется сохранять или использовать в веб-сервисах.
⚠️ РАССМОТРИТЕ поддержку сериализации XML вместо или в дополнение к Data Contract, если вам нужен больший контроль над форматом XML, который создается при сериализации типа. Это может быть необходимо в некоторых сценариях взаимодействия, где необходимо использовать конструкции XML, которые не поддерживаются сериализацией Data Contract, например, для создания атрибутов XML.
⚠️ РАССМОТРИТЕ поддержку сериализации времени выполнения, если экземпляры вашего типа должны перемещаться через границы .NET Remoting.
Поддержка сериализации Data Contract
Типы могут поддерживать сериализацию Data Contract, применяя атрибуты
DataContract
к типу и DataMember
к элементам (полям и свойствам) типа.⚠️ РАССМОТРИТЕ возможность сделать члены вашего типа открытыми, если тип может использоваться в средах с частичным доверием. В среде с полным доверием сериализаторы Data Contract могут сериализовать и десериализовать непубличные типы и члены.
❗️ НЕОБХОДИМО использовать и аксессор (get), и мутатор (set) для всех свойств, имеющих атрибут
DataMember
. В .NET Framework 3.5 SP1 некоторые свойства коллекции могут быть доступны только для чтения. Если тип не будет использоваться в средах с частичным доверием, аксессор и мутатор могут быть закрытыми.⚠️ РАССМОТРИТЕ использование обратных вызовов сериализации для инициализации десериализованных экземпляров. За редкими исключениями, при десериализации объектов конструкторы не вызываются. Следовательно, любая логика, которая выполняется во время обычного создания объекта, должна быть реализована в методе обратного вызова. Методы обратного вызова помечаются атрибутами
OnSerializing
, OnSerialized
, OnDeserializing
, OnDeserialized
.⚠️ РАССМОТРИТЕ использование атрибута
KnownType
, чтобы указать конкретные типы, которые следует использовать при десериализации графа сложного объекта.❗️ НЕОБХОДИМО учитывать обратную и прямую совместимость при создании или изменении сериализуемых типов. Помните, что сериализованные потоки новых версий вашего типа могут быть десериализованы в старую версию типа, и наоборот. Учтите, что члены данных, даже закрытые и внутренние, не могут изменять свои имена, типы или даже порядок в новых версиях типа, если не будут приняты особые меры для сохранения контракта с использованием явных параметров атрибутов Data Contract. Проверьте совместимость сериализации при внесении изменений в сериализуемые типы. Попробуйте десериализовать новую версию в старую и наоборот.
⚠️ РАССМОТРИТЕ реализацию
IExtensibleDataObject
, чтобы разрешить циклический переход между различными версиями типа. Интерфейс позволяет сериализатору гарантировать, что никакие данные не будут потеряны во время такого перехода. Свойство IExtensibleDataObject.ExtensionData
используется для хранения любых данных из будущей версии типа, которые неизвестны текущей версии, и не могут быть сохранены в текущей версии. Когда текущая версия впоследствии сериализуется и десериализуется в будущую версию, дополнительные данные будут доступны в сериализованном потоке.Продолжение следует…
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести девяносто седьмой. #BestPractices
Советы по сериализации. Окончание
Поддержка XML-сериализации
Сериализация Data Contract является основной технологией сериализации в .NET Framework, но существуют сценарии, которые она не поддерживает. Например, она не даёт вам полного контроля над форматом XML, создаваемым или потребляемым сериализатором. Если требуется такой точный контроль, необходимо использовать сериализацию XML, и разработать типы с поддержкой этой технологии сериализации.
❌ ИЗБЕГАЙТЕ разработки ваших типов специально для XML-сериализации, если только у вас нет веских оснований контролировать формат создаваемого XML. Эта технология сериализации была заменена сериализацией Data Contract, рассмотренной в предыдущем посте.
⚠️ РАССМОТРИТЕ реализацию интерфейса
Поддержка сериализации времени выполнения
Сериализация времени выполнения - это технология, используемая в .NET Remoting. Если вы думаете, что ваши типы будут транспортироваться с помощью .NET Remoting, вам необходимо убедиться, что они поддерживают сериализацию времени выполнения.
Базовая поддержка сериализации времени выполнения может быть обеспечена путем применения атрибута
⚠️ РАССМОТРИТЕ поддержку сериализации времени выполнения, если ваши типы будут использоваться в .NET Remoting. Например, пространство имен
⚠️ РАССМОТРИТЕ реализацию паттерна сериализации времени выполнения, если вы хотите полностью контролировать процесс сериализации. Например, преобразовывать данные по мере их сериализации или десериализации.Для этого нужно реализовать интерфейс
✅ ИСПОЛЬЗУЙТЕ защищённый конструктор сериализации с двумя параметрами, как показано ниже:
❗️ НЕОБХОДИМО применить атрибут
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
Советы по сериализации. Окончание
Поддержка XML-сериализации
Сериализация Data Contract является основной технологией сериализации в .NET Framework, но существуют сценарии, которые она не поддерживает. Например, она не даёт вам полного контроля над форматом XML, создаваемым или потребляемым сериализатором. Если требуется такой точный контроль, необходимо использовать сериализацию XML, и разработать типы с поддержкой этой технологии сериализации.
❌ ИЗБЕГАЙТЕ разработки ваших типов специально для XML-сериализации, если только у вас нет веских оснований контролировать формат создаваемого XML. Эта технология сериализации была заменена сериализацией Data Contract, рассмотренной в предыдущем посте.
⚠️ РАССМОТРИТЕ реализацию интерфейса
IXmlSerializable
, если вы хотите получить больший контроль над форматом сериализованного XML, чем просто применение атрибутов XML-сериализации. Два метода интерфейса, ReadXml
и WriteXml
, позволяют полностью контролировать сериализованный поток XML. Вы также можете управлять схемой XML применяя атрибут XmlSchemaProvider
.Поддержка сериализации времени выполнения
Сериализация времени выполнения - это технология, используемая в .NET Remoting. Если вы думаете, что ваши типы будут транспортироваться с помощью .NET Remoting, вам необходимо убедиться, что они поддерживают сериализацию времени выполнения.
Базовая поддержка сериализации времени выполнения может быть обеспечена путем применения атрибута
Serializable
, а более сложные сценарии включают реализацию простого паттерна сериализации времени выполнения (реализуйте ISerializable
и предоставьте конструктор сериализации).⚠️ РАССМОТРИТЕ поддержку сериализации времени выполнения, если ваши типы будут использоваться в .NET Remoting. Например, пространство имен
System.AddIn
использует .NET Remoting, поэтому все типы, которыми обмениваются надстройки System.AddIn
, должны поддерживать сериализацию времени выполнения.⚠️ РАССМОТРИТЕ реализацию паттерна сериализации времени выполнения, если вы хотите полностью контролировать процесс сериализации. Например, преобразовывать данные по мере их сериализации или десериализации.Для этого нужно реализовать интерфейс
ISerializable
и предоставить специальный конструктор, который используется при десериализации объекта.✅ ИСПОЛЬЗУЙТЕ защищённый конструктор сериализации с двумя параметрами, как показано ниже:
[Serializable]❗️ НЕОБХОДИМО явно реализовать элементы ISerializable.
public class Person : ISerializable
{
protected Person(SerializationInfo info, StreamingContext context) {…}
}
❗️ НЕОБХОДИМО применить атрибут
SecurityPermission(SecurityAction.LinkDemand)
к реализации ISerializable.GetObjectData
. Это гарантирует, что только полностью доверенный код получит доступ к методу.Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести девяносто восьмой. #Оффтоп
Хорошая картинка, посвящённая дизайну, основанному на пользовательском опыте, (UX-driven design) из лекции Дино Эспозито на конференции DotNext. С точки зрения пользователя наш софт – это слой представления и чёрный ящик. Поэтому дизайн, основанный на пользовательском опыте, предполагает сначала выяснение, какой функционал требуется конечному пользователю, а только затем дизайн кнопок - триггеров операций в бэкэнде, который для пользователя представляет собой чёрный ящик. То, что в чёрном ящике, пользователя не волнует. Важны команды, которые он туда посылает и результаты, которые он из него получает. Когда есть согласие с пользователем относительно презентационного слоя, большинство проблем использования, обычно возникающих после релиза продукта, решаются на ранних этапах проектирования.
Полная лекция (на английском): https://youtu.be/xeMbZyhzoAw
Хорошая картинка, посвящённая дизайну, основанному на пользовательском опыте, (UX-driven design) из лекции Дино Эспозито на конференции DotNext. С точки зрения пользователя наш софт – это слой представления и чёрный ящик. Поэтому дизайн, основанный на пользовательском опыте, предполагает сначала выяснение, какой функционал требуется конечному пользователю, а только затем дизайн кнопок - триггеров операций в бэкэнде, который для пользователя представляет собой чёрный ящик. То, что в чёрном ящике, пользователя не волнует. Важны команды, которые он туда посылает и результаты, которые он из него получает. Когда есть согласие с пользователем относительно презентационного слоя, большинство проблем использования, обычно возникающих после релиза продукта, решаются на ранних этапах проектирования.
Полная лекция (на английском): https://youtu.be/xeMbZyhzoAw
День двести девяносто девятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
9. Сначала проверьте свой код, прежде чем обвинять других
Признайтесь, каждому из нас хоть раз было трудно признаться себе, что наш код не работает. Этого
просто не может быть! Это настолько невероятно, что наверняка именно в этот раз проблема должна
быть в компиляторе/фреймворке/библиотеке.
Но на самом деле это крайне – крайне! – маловероятно, что работа кода нарушается из-за ошибки в
компиляторе, интерпретаторе, ОС, сервере приложений, фреймворке, базе данных, диспетчере памяти или любом другом компоненте системного программного обеспечения. Да, эти ошибки существуют, но они встречаются гораздо реже, чем нам хотелось бы верить.
Однажды я в самом деле столкнулся с ошибкой компилятора, который при оптимизации выкидывал
переменную цикла, но грешил на ошибку в компиляторе или ОС я гораздо чаще. Я тратил много своего времени и времени техподдержки, только чтобы в итоге чувствовать себя идиотом каждый раз, когда в конце концов оказывалось, что ошибка была у меня.
Если инструмент широко распространён и используется множеством людей в различных ситуациях, то причин сомневаться в его качестве очень мало. Конечно, если это бета-версия инструмента или он используется всего несколькими людьми? или же это проект с открытым кодом на ранних стадиях разработки, могут быть веские основания подозревать его.
Но учитывая, насколько редки ошибки в компиляторах, вы гораздо лучше потратите своё время и энергию на поиск ошибки в своем коде, чем на доказательство того, что компилятор не прав. Применимы все обычные рекомендации по отладке.
Когда кто-то другой сообщает о проблеме, которую вы не можете воспроизвести, сходите и посмотрите, что он делает. Люди могут делать то, о чём вы никогда бы не подумали, или делать что-то в другом порядке.
Проблемы с многопоточностью также являются очень частым источником ошибок, заставляющим седеть и орать на компьютер. Все рекомендации в пользу написания простого кода становятся на порядок важнее, когда система многопоточная. При поиске таких ошибок нельзя уверенно полагаться на отладку и модульные тесты, поэтому простота проектирования имеет первостепенное значение.
Итак, прежде чем спешить обвинять компилятор, фреймворк или библиотеку вспомните совет Шерлока Холмса: «После того, как вы исключили невозможное, то всё, что осталось, независимо от того, насколько невероятным оно выглядит, является истиной», и отдавайте предпочтение именно ему, а не правилу Дирка Джентли: «После того, как вы исключили невероятное, всё, что осталось, независимо от того, насколько невозможным оно выглядит, является истиной».
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Allan Kelly
97 Вещей, Которые Должен Знать Каждый Программист
9. Сначала проверьте свой код, прежде чем обвинять других
Признайтесь, каждому из нас хоть раз было трудно признаться себе, что наш код не работает. Этого
просто не может быть! Это настолько невероятно, что наверняка именно в этот раз проблема должна
быть в компиляторе/фреймворке/библиотеке.
Но на самом деле это крайне – крайне! – маловероятно, что работа кода нарушается из-за ошибки в
компиляторе, интерпретаторе, ОС, сервере приложений, фреймворке, базе данных, диспетчере памяти или любом другом компоненте системного программного обеспечения. Да, эти ошибки существуют, но они встречаются гораздо реже, чем нам хотелось бы верить.
Однажды я в самом деле столкнулся с ошибкой компилятора, который при оптимизации выкидывал
переменную цикла, но грешил на ошибку в компиляторе или ОС я гораздо чаще. Я тратил много своего времени и времени техподдержки, только чтобы в итоге чувствовать себя идиотом каждый раз, когда в конце концов оказывалось, что ошибка была у меня.
Если инструмент широко распространён и используется множеством людей в различных ситуациях, то причин сомневаться в его качестве очень мало. Конечно, если это бета-версия инструмента или он используется всего несколькими людьми? или же это проект с открытым кодом на ранних стадиях разработки, могут быть веские основания подозревать его.
Но учитывая, насколько редки ошибки в компиляторах, вы гораздо лучше потратите своё время и энергию на поиск ошибки в своем коде, чем на доказательство того, что компилятор не прав. Применимы все обычные рекомендации по отладке.
Когда кто-то другой сообщает о проблеме, которую вы не можете воспроизвести, сходите и посмотрите, что он делает. Люди могут делать то, о чём вы никогда бы не подумали, или делать что-то в другом порядке.
Проблемы с многопоточностью также являются очень частым источником ошибок, заставляющим седеть и орать на компьютер. Все рекомендации в пользу написания простого кода становятся на порядок важнее, когда система многопоточная. При поиске таких ошибок нельзя уверенно полагаться на отладку и модульные тесты, поэтому простота проектирования имеет первостепенное значение.
Итак, прежде чем спешить обвинять компилятор, фреймворк или библиотеку вспомните совет Шерлока Холмса: «После того, как вы исключили невозможное, то всё, что осталось, независимо от того, насколько невероятным оно выглядит, является истиной», и отдавайте предпочтение именно ему, а не правилу Дирка Джентли: «После того, как вы исключили невероятное, всё, что осталось, независимо от того, насколько невозможным оно выглядит, является истиной».
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Allan Kelly
День трёхсотый. #ВопросыНаСобеседовании
Юбилейный день – самое время начать новый тред)))
Самые часто задаваемые вопросы на собеседовании по ASP.NET MVC
1. Что такое MVC (Model-View-Controller)?
Модель–представление–контроллер (MVC) - это паттерн архитектуры ПО для разделения данных приложения, пользовательского интерфейса и управляющей логики на три отдельных компонента: модель, представление и контроллер — таким образом, что модификация каждого компонента может осуществляться независимо. ASP.NET MVC - это фреймворк для создания веб-приложений с использованием паттерна MVC.
Модель реализует бизнес-логику приложения. Объекты модели хранят данные модели и зачастую взаимодействуют с базой данных.
Представление реализует отображение данных. Чаще всего представления создаются на основе данных модели.
Контроллер обрабатывает взаимодействие с пользователем (запросы пользователя к страницам, либо данные, введённые пользователем в форму представления), взаимодействует с моделью (запрашивает или обновляет данные) и возвращает ответ (данные в представлении).
Разделение MVC помогает управлять сложными приложениями, потому что вы можете сосредоточиться на одной области за раз. Например, работать с представлением, не трогая бизнес-логику. Это также облегчает тестирование приложения. Кроме того, различные разработчики могут работать над представлением, логикой контроллера или бизнес-логикой параллельно.
Источник: https://www.c-sharpcorner.com
Юбилейный день – самое время начать новый тред)))
Самые часто задаваемые вопросы на собеседовании по ASP.NET MVC
1. Что такое MVC (Model-View-Controller)?
Модель–представление–контроллер (MVC) - это паттерн архитектуры ПО для разделения данных приложения, пользовательского интерфейса и управляющей логики на три отдельных компонента: модель, представление и контроллер — таким образом, что модификация каждого компонента может осуществляться независимо. ASP.NET MVC - это фреймворк для создания веб-приложений с использованием паттерна MVC.
Модель реализует бизнес-логику приложения. Объекты модели хранят данные модели и зачастую взаимодействуют с базой данных.
Представление реализует отображение данных. Чаще всего представления создаются на основе данных модели.
Контроллер обрабатывает взаимодействие с пользователем (запросы пользователя к страницам, либо данные, введённые пользователем в форму представления), взаимодействует с моделью (запрашивает или обновляет данные) и возвращает ответ (данные в представлении).
Разделение MVC помогает управлять сложными приложениями, потому что вы можете сосредоточиться на одной области за раз. Например, работать с представлением, не трогая бизнес-логику. Это также облегчает тестирование приложения. Кроме того, различные разработчики могут работать над представлением, логикой контроллера или бизнес-логикой параллельно.
Источник: https://www.c-sharpcorner.com
День триста первый. #Оффтоп
Затарился книжечками, чтобы не скучать в новом году)))
Затарился книжечками, чтобы не скучать в новом году)))
День триста третий. #BestPractices
Операторы Равенства
Далее обсуждаются перегрузки операторов равенства (
❌ ИЗБЕГАЙТЕ перегрузки одного из операторов равенства без перегрузки другого.
❗️ НЕОБХОДИМО убедиться, что
❌ ИЗБЕГАЙТЕ выброса исключений из операторов равенства. Например, возвращайте
Операторы равенства в значимых типах
✅ ИСПОЛЬЗУЙТЕ перегрузку операторов равенства для значимых типов, если имеет смысл сравнивать объекты этого типа. В большинстве языков программирования отсутствует стандартная реализация
Операторы равенства в ссылочных типах
❌ ИЗБЕГАЙТЕ перегрузки операторов равенства в изменяемых ссылочных типах. Многие языки имеют встроенные операторы равенства для ссылочных типов. Встроенные операторы обычно проверяют на равенство ссылки на объекты, и многие разработчики удивляются, когда поведение по умолчанию изменяется на проверку равенства значений. Эта проблема менее актуальна для неизменяемых ссылочных типов, потому что для неизменяемых типов разница между ссылочным равенством и равенством значений менее принципиальна.
❌ ИЗБЕГАЙТЕ перегрузки операторов равенства в ссылочных типах, если реализация будет значительно медленнее, чем реализация ссылочного равенства.
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
Операторы Равенства
Далее обсуждаются перегрузки операторов равенства (
operator==
и operator!=
).❌ ИЗБЕГАЙТЕ перегрузки одного из операторов равенства без перегрузки другого.
❗️ НЕОБХОДИМО убедиться, что
Object.Equals
и операторы равенства имеют одинаковую семантику и схожие характеристики производительности. Чаще всего это означает, что необходимо переопределить Object.Equals
, когда операторы равенства перегружены.❌ ИЗБЕГАЙТЕ выброса исключений из операторов равенства. Например, возвращайте
false
, если один из аргументов имеет значение null
, а не выбрасывайте NullReferenceException
.Операторы равенства в значимых типах
✅ ИСПОЛЬЗУЙТЕ перегрузку операторов равенства для значимых типов, если имеет смысл сравнивать объекты этого типа. В большинстве языков программирования отсутствует стандартная реализация
operator==
для значимых типов.Операторы равенства в ссылочных типах
❌ ИЗБЕГАЙТЕ перегрузки операторов равенства в изменяемых ссылочных типах. Многие языки имеют встроенные операторы равенства для ссылочных типов. Встроенные операторы обычно проверяют на равенство ссылки на объекты, и многие разработчики удивляются, когда поведение по умолчанию изменяется на проверку равенства значений. Эта проблема менее актуальна для неизменяемых ссылочных типов, потому что для неизменяемых типов разница между ссылочным равенством и равенством значений менее принципиальна.
❌ ИЗБЕГАЙТЕ перегрузки операторов равенства в ссылочных типах, если реализация будет значительно медленнее, чем реализация ссылочного равенства.
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/