День двести семьдесят пятый. #ЗаметкиНаПолях
Сопоставление с шаблоном. Продолжение
В C#7 представлены три вида шаблонов: шаблоны констант, шаблоны типов и шаблон var. Использовать сопоставление с шаблоном можно в двух контекстах: в операторе
Шаблоны констант
Шаблон констант соответствует своему названию: он представляет собой константное выражение времени компиляции, которое затем проверяется на равенство с входными данными. Если и входные данные, и константа являются целочисленными выражениями, они сравниваются с помощью
Шаблоны типов
Шаблон типа состоит из типа и идентификатора, похожего на объявление переменной. Шаблон соответствует, если входной параметр является значением этого типа, что похоже на обычный оператор
Шаблон типа обычно используется для замены либо комбинации
Но можно использовать параметр типа, который в свою очередь может быть обнуляемым значимым типом:
Шаблон var
Шаблон var выглядит как шаблон типа, но в качестве типа используется
В C#8 введены возможности сопоставления с шаблоном ещё более расширены.
Продолжение следует…
Источник: Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 12.
Сопоставление с шаблоном. Продолжение
В C#7 представлены три вида шаблонов: шаблоны констант, шаблоны типов и шаблон var. Использовать сопоставление с шаблоном можно в двух контекстах: в операторе
is
и операторе switch
. Каждый шаблон пытается соответствовать входным данных. Это может быть любое выражение, не содержащее указателей.Шаблоны констант
Шаблон констант соответствует своему названию: он представляет собой константное выражение времени компиляции, которое затем проверяется на равенство с входными данными. Если и входные данные, и константа являются целочисленными выражениями, они сравниваются с помощью
==
. В противном случае вызывается статический метод object.Equals
, который позволяет безопасно проверять на null
. Например:static void Match(object input)Вывод в основном понятен, кроме последней строки:
{
if (input is "hello")
Console.WriteLine("Это строка hello");
else if (input is 10)
Console.WriteLine("Это значение int 10");
else
Console.WriteLine("Совпадений не найдено");
}
static void Main()
{
Match("hello");
Match(10);
Match(10L);
}
Это строка helloЕсли целые числа сравниваются с использованием ==, почему последний вызов
Это значение int 10
Совпадений не найдено
Match(10L)
не находит совпадений? Дело в том, что тип ввода во время компиляции не является целочисленным типом, это объект, поэтому компилятор генерирует код, эквивалентный вызову object.Equals(x, 10)
. А он возвращает false
, т.к. значение x представляет собой упакованное Int64
, а не упакованное Int32
.Шаблоны типов
Шаблон типа состоит из типа и идентификатора, похожего на объявление переменной. Шаблон соответствует, если входной параметр является значением этого типа, что похоже на обычный оператор
is
. Преимущество использования шаблона в том, что он также вводит новую переменную шаблона этого типа, инициализируемую значением, если шаблон соответствует. Если шаблон не совпадёт, переменная всё равно будет существовать, но не будет определена. Если на входе null
, он не будет соответствовать ни одному типу. Также можно использовать пустую переменную _
, тогда переменная не будет создана. Пример использования шаблона типа был в предыдущем посте. Шаблон типа обычно используется для замены либо комбинации
as
/if
, либо, блока if
с приведением типов. Тип, указанный в шаблоне типа, не может быть обнуляемым значимым типом. То есть нельзя написать:if (value is int? t)...
Но можно использовать параметр типа, который в свою очередь может быть обнуляемым значимым типом:
static void CheckType<T>(object value)В этом случае шаблон найдёт соответствие только тогда, когда значение не равно
{
if (value is T t)
Console.WriteLine(t);
}
CheckType<int?>(null);
CheckType<int?>(5);
null
.Шаблон var
Шаблон var выглядит как шаблон типа, но в качестве типа используется
var
:someExpression is var xКак и шаблоны типов, он вводит новую переменную, но ничего не проверяет. Он всегда совпадает (даже с
null
), в результате чего получается новая переменная с тем же типом и значением, что и у входного параметра. Поэтому этот шаблон бесполезен в операторе is
, а используется в операторе switch
в качестве последнего варианта, когда все остальные шаблоны не совпали. В C#8 введены возможности сопоставления с шаблоном ещё более расширены.
Продолжение следует…
Источник: Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 12.
День двести семьдесят шестой. #ЗаметкиНаПолях
Сопоставление с шаблоном. Окончание
Охранные выражения
Помимо простого сравнения с шаблоном в блоке case вы можете использовать новый фрагмент синтаксиса – охранное выражение после ключевого слова
Область видимости
Областью видимости переменной шаблона является блок кода, включающий выражение. У этого есть как преимущества, так и недостатки. Недостатком является то, что переменная шаблона может быть не определена, если совпадения с шаблоном не произойдёт. То есть использовать переменную
Если переменная объявляется непосредственно в теле
Порядок оценки операторов switch при сопоставлении с шаблоном
Почти во всех ситуациях порядок блоков case при сравнении с константами не имеет значения, потому что каждый блок соответствует одному постоянному значению, а используемые константы должны быть разными. С шаблонами это не так. Порядок оценки оператора
- Каждое условие оценивается в порядке следования в коде.
- Тело блока
Тут на помощь приходит компилятор: случай без охранного выражения всегда выполнится, если шаблон типа совпадёт. Компилятор знает об этом, поэтому, если вы поместите выше случаи, «скрывающие» те, что следуют за ними, компилятор сообщит об ошибке.
Источник: Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 12.
Сопоставление с шаблоном. Окончание
Охранные выражения
Помимо простого сравнения с шаблоном в блоке case вы можете использовать новый фрагмент синтаксиса – охранное выражение после ключевого слова
when
:case pattern when expression:Выражение должно соответствовать булеву значению, так же как условие оператора
if
. Тело case
будет выполнено, только если выражение истинно. Выражение может использовать шаблоны, тем самым вводя дополнительные переменные шаблона. Например:switch (obj)Когда вы используете охранные выражения, вполне возможно использовать один и тот же шаблон несколько раз, потому что при первом совпадении с шаблоном охранное выражение может вернуть
{
case Shape shape when shape.Area == 0:
…
break;
case Rectangle rect when rect.Area > 0:
…
break;
case Circle circle when circle.Area > 0:
…
break;
case Shape shape:
…
break;
case null:
…
break;
default:
…
break;
}
false
.Область видимости
Областью видимости переменной шаблона является блок кода, включающий выражение. У этого есть как преимущества, так и недостатки. Недостатком является то, что переменная шаблона может быть не определена, если совпадения с шаблоном не произойдёт. То есть использовать переменную
text
внутри блока if
безопасно, а после - нет:if (input is string text)С другой стороны, переменная определяется сразу же в шаблоне, таким образом можно использовать следующую конструкцию:
{
Console.WriteLine(text);
}
if (input is int x && x > 100)Вы можете использовать
{
Console.WriteLine($"Это большое целое число: {x}");
}
x
после &&
, потому что это выражение оценивается, только если первый операнд оценивается как истина. Можно использовать x
внутри оператора if
, потому что оно выполняется, только если оба операнда истинны.Если переменная объявляется непосредственно в теле
case
, область действия этой переменной - весь оператор switch
, включая другие блоки case
. Но это не включает переменные, объявленные в самих блоках case
. Область действия этих переменных - только тело соответствующего блока case
.Порядок оценки операторов switch при сопоставлении с шаблоном
Почти во всех ситуациях порядок блоков case при сравнении с константами не имеет значения, потому что каждый блок соответствует одному постоянному значению, а используемые константы должны быть разными. С шаблонами это не так. Порядок оценки оператора
switch
на основе шаблона можно описать так:- Каждое условие оценивается в порядке следования в коде.
- Тело блока
default
выполняется только после того, как все остальные условия были проверены, независимо от того, где оно расположено в операторе switch
.Тут на помощь приходит компилятор: случай без охранного выражения всегда выполнится, если шаблон типа совпадёт. Компилятор знает об этом, поэтому, если вы поместите выше случаи, «скрывающие» те, что следуют за ними, компилятор сообщит об ошибке.
Источник: Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 12.
День двести семьдесят седьмой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
6. Перед началом рефакторинга
В какой-то момент каждому программисту приходится делать рефакторинг уже существующего кода. Но, прежде чем сделать это, подумайте о следующем, так как это может сэкономить вам и другим много времени (и боли):
1. Наилучший подход к реструктуризации начинается с оценки существующей кодовой базы и тестов, написанных для этого кода. Это поможет вам понять сильные и слабые стороны кода в его нынешнем виде, чтобы вы могли сохранить сильные стороны и избежать ошибок. Мы все думаем, что можем сделать лучше, чем то, что уже существует… пока не получаем нечто такое же или даже хуже того, что было, потому что мы не смогли извлечь уроки из ошибок существующей системы.
2. Избегайте соблазна переписать всё. Лучше всего использовать как можно больше существующего кода. Независимо от того, насколько он уродлив, он уже был протестирован, проверен и т. д. Выбрасывая старый код, особенно если он был в продакшене, вы выбрасываете месяцы (или годы) проверенного, закаленного в боях кода, который, возможно, имел определённые обходные пути и обрабатывал ошибки, о которых вы не знаете. Если вы не принимаете это во внимание, новый код, который вы пишете, может в конечном итоге выдавать те же загадочные ошибки, которые были исправлены в старом коде. Это впустую потратит время, усилия и знания, полученные за эти годы.
3. Несколько последовательных изменений лучше, чем одно большое. Инкрементные изменения позволяют легче оценить влияние на систему с помощью обратной связи, например, от тестов. Неприятно видеть сотню неудачных тестов после внесения изменений. Это разочаровывает и раздражает, что, в свою очередь, может привести к неправильным решениям. Пару неудачных тестов за раз легче исправить, что приводит к более управляемому подходу.
4. После каждой итерации разработки важно убедиться, что существующие тесты успешно проходят. Добавьте новые тесты, если существующих тестов недостаточно, чтобы покрыть внесённые вами изменения. Не выбрасывайте тесты старого кода без должного анализа. На первый взгляд, некоторые из этих тестов могут показаться неприменимыми к вашему новому дизайну, но стоит разобраться в причинах, по которым этот конкретный тест был добавлен.
5. Личные предпочтения и эго не должны мешать. Если что-то работает, зачем это чинить? То, что стиль или структура кода не соответствуют вашим личным предпочтениям, не является уважительной причиной для рефакторинга. Уверенность, что вы могли бы написать лучше, чем предыдущий программист, также не является веским основанием.
6. Новая технология не является достаточной причиной для рефакторинга. Одна из худших причин для рефакторинга заключается в том, что текущий код не использует все крутые технологии, которыми мы располагаем сегодня, и уверенность, что новый язык или инфраструктура могут делать вещи более элегантно. Если анализ затрат и выгод не покажет, что новый язык или структура приведут к значительным улучшениям в функциональности, удобстве обслуживания или производительности, лучше оставить всё как есть.
7. Помните, что люди ошибаются. Реструктуризация не всегда гарантирует, что новый код будет лучше или хотя бы таким же хорошим, как предыдущая версия. Это неприятно, но такова человеческая природа.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
97 Вещей, Которые Должен Знать Каждый Программист
6. Перед началом рефакторинга
В какой-то момент каждому программисту приходится делать рефакторинг уже существующего кода. Но, прежде чем сделать это, подумайте о следующем, так как это может сэкономить вам и другим много времени (и боли):
1. Наилучший подход к реструктуризации начинается с оценки существующей кодовой базы и тестов, написанных для этого кода. Это поможет вам понять сильные и слабые стороны кода в его нынешнем виде, чтобы вы могли сохранить сильные стороны и избежать ошибок. Мы все думаем, что можем сделать лучше, чем то, что уже существует… пока не получаем нечто такое же или даже хуже того, что было, потому что мы не смогли извлечь уроки из ошибок существующей системы.
2. Избегайте соблазна переписать всё. Лучше всего использовать как можно больше существующего кода. Независимо от того, насколько он уродлив, он уже был протестирован, проверен и т. д. Выбрасывая старый код, особенно если он был в продакшене, вы выбрасываете месяцы (или годы) проверенного, закаленного в боях кода, который, возможно, имел определённые обходные пути и обрабатывал ошибки, о которых вы не знаете. Если вы не принимаете это во внимание, новый код, который вы пишете, может в конечном итоге выдавать те же загадочные ошибки, которые были исправлены в старом коде. Это впустую потратит время, усилия и знания, полученные за эти годы.
3. Несколько последовательных изменений лучше, чем одно большое. Инкрементные изменения позволяют легче оценить влияние на систему с помощью обратной связи, например, от тестов. Неприятно видеть сотню неудачных тестов после внесения изменений. Это разочаровывает и раздражает, что, в свою очередь, может привести к неправильным решениям. Пару неудачных тестов за раз легче исправить, что приводит к более управляемому подходу.
4. После каждой итерации разработки важно убедиться, что существующие тесты успешно проходят. Добавьте новые тесты, если существующих тестов недостаточно, чтобы покрыть внесённые вами изменения. Не выбрасывайте тесты старого кода без должного анализа. На первый взгляд, некоторые из этих тестов могут показаться неприменимыми к вашему новому дизайну, но стоит разобраться в причинах, по которым этот конкретный тест был добавлен.
5. Личные предпочтения и эго не должны мешать. Если что-то работает, зачем это чинить? То, что стиль или структура кода не соответствуют вашим личным предпочтениям, не является уважительной причиной для рефакторинга. Уверенность, что вы могли бы написать лучше, чем предыдущий программист, также не является веским основанием.
6. Новая технология не является достаточной причиной для рефакторинга. Одна из худших причин для рефакторинга заключается в том, что текущий код не использует все крутые технологии, которыми мы располагаем сегодня, и уверенность, что новый язык или инфраструктура могут делать вещи более элегантно. Если анализ затрат и выгод не покажет, что новый язык или структура приведут к значительным улучшениям в функциональности, удобстве обслуживания или производительности, лучше оставить всё как есть.
7. Помните, что люди ошибаются. Реструктуризация не всегда гарантирует, что новый код будет лучше или хотя бы таким же хорошим, как предыдущая версия. Это неприятно, но такова человеческая природа.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
День двести семьдесят восьмой. #BestPractices
Советы по использованию общих типов
Атрибуты
Атрибуты - это аннотации, которые можно добавлять к программным элементам (сборкам, типам, членам и параметрам). Атрибуты могут иметь одно или несколько свойств, которые содержат дополнительные данные, связанные с атрибутом. Некоторые свойства атрибута должны быть указаны при применении атрибута. Они называются обязательными свойствами или обязательными аргументами, и представлены как позиционные параметры конструктора. Свойства, которые не обязательно указывать при применении атрибута, называются необязательными. Они задаются именованными параметрами конструктора.
✅ ИСПОЛЬЗУЙТЕ суффикс
❗️ НЕОБХОДИМО применять атрибут
✅ ИСПОЛЬЗУЙТЕ изменяемые свойства для необязательных аргументов атрибута.
✅ ИСПОЛЬЗУЙТЕ неизменяемые (только
✅ ИСПОЛЬЗУЙТЕ параметры конструктора для инициализации свойств, соответствующих обязательным аргументам. Каждый параметр должен иметь то же имя (отличающееся регистром), что и соответствующее свойство.
❌ ИЗБЕГАЙТЕ добавления параметров конструктора для инициализации свойств, соответствующих необязательным аргументам. Другими словами, не создавайте в классе атрибута свойств, которые могут быть установлены как с помощью конструктора, так и с помощью аксессора. Чётко определите, какие аргументы являются обязательными, а какие нет, и избегайте наличия двух способов сделать одно и то же.
❌ ИЗБЕГАЙТЕ перегрузки пользовательских конструкторов атрибутов. Наличие только одного конструктора четко сообщает пользователю атрибута, какие аргументы являются обязательными, а какие - необязательными.
✅ ИСПОЛЬЗУЙТЕ закрытые (
Подробнее об атрибутах здесь, здесь и здесь.
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
Советы по использованию общих типов
Атрибуты
System.Attribute
- это базовый класс, используемый для определения пользовательских атрибутов.Атрибуты - это аннотации, которые можно добавлять к программным элементам (сборкам, типам, членам и параметрам). Атрибуты могут иметь одно или несколько свойств, которые содержат дополнительные данные, связанные с атрибутом. Некоторые свойства атрибута должны быть указаны при применении атрибута. Они называются обязательными свойствами или обязательными аргументами, и представлены как позиционные параметры конструктора. Свойства, которые не обязательно указывать при применении атрибута, называются необязательными. Они задаются именованными параметрами конструктора.
✅ ИСПОЛЬЗУЙТЕ суффикс
Attribute
в именах классов пользовательских атрибутов.❗️ НЕОБХОДИМО применять атрибут
AttributeUsageAttribute
к классам пользовательских атрибутов.✅ ИСПОЛЬЗУЙТЕ изменяемые свойства для необязательных аргументов атрибута.
✅ ИСПОЛЬЗУЙТЕ неизменяемые (только
get
) свойства для обязательных аргументов атрибута.✅ ИСПОЛЬЗУЙТЕ параметры конструктора для инициализации свойств, соответствующих обязательным аргументам. Каждый параметр должен иметь то же имя (отличающееся регистром), что и соответствующее свойство.
❌ ИЗБЕГАЙТЕ добавления параметров конструктора для инициализации свойств, соответствующих необязательным аргументам. Другими словами, не создавайте в классе атрибута свойств, которые могут быть установлены как с помощью конструктора, так и с помощью аксессора. Чётко определите, какие аргументы являются обязательными, а какие нет, и избегайте наличия двух способов сделать одно и то же.
❌ ИЗБЕГАЙТЕ перегрузки пользовательских конструкторов атрибутов. Наличие только одного конструктора четко сообщает пользователю атрибута, какие аргументы являются обязательными, а какие - необязательными.
✅ ИСПОЛЬЗУЙТЕ закрытые (
sealed
) классы для атрибутов, если это возможно. Это ускоряет поиск атрибута.Подробнее об атрибутах здесь, здесь и здесь.
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести семьдесят девятый. #юмор
Профессиональное выгорание. Не допускайте этого)))
Профессиональное выгорание. Не допускайте этого)))
День двести восьмидесятый. #BestPractices
Советы по использованию общих типов
Коллекции. Начало
Любой тип, разработанный специально для управления группой объектов, имеющих некоторую общую характеристику, может считаться коллекцией. Для таких типов почти всегда целесообразно реализовывать интерфейсы
❌ ИЗБЕГАЙТЕ использования слабо типизированных коллекций в общедоступных API. Тип всех возвращаемых значений и параметров, представляющих элементы коллекции, должен быть точным типом элемента, а не каким-либо из его базовых типов (это относится только к открытым членам коллекции).
❌ ИЗБЕГАЙТЕ использования
❌ ИЗБЕГАЙТЕ использования
❌ ИЗБЕГАЙТЕ использования
❌ ИЗБЕГАЙТЕ использования обоих интерфейсов
Параметры коллекции
✅ ИСПОЛЬЗУЙТЕ наименее специализированный возможный тип в качестве типа параметра. Большинство членов, принимающих коллекции в качестве параметров, используют интерфейс
❌ ИЗБЕГАЙТЕ использования
Продолжение следует...
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
Советы по использованию общих типов
Коллекции. Начало
Любой тип, разработанный специально для управления группой объектов, имеющих некоторую общую характеристику, может считаться коллекцией. Для таких типов почти всегда целесообразно реализовывать интерфейсы
IEnumerable
или IEnumerable<T>
, поэтому далее мы рассматриваем только типы, реализующие один или оба этих интерфейса.❌ ИЗБЕГАЙТЕ использования слабо типизированных коллекций в общедоступных API. Тип всех возвращаемых значений и параметров, представляющих элементы коллекции, должен быть точным типом элемента, а не каким-либо из его базовых типов (это относится только к открытым членам коллекции).
❌ ИЗБЕГАЙТЕ использования
ArrayList
или List<T>
в открытых API. Эти типы являются структурами данных, предназначенными для использования во внутренней реализации, а не в публичных API. List<T>
оптимизирован для производительности за счет гибкости и чистоты API. Например, если вы вернёте List<T>
, вы никогда не сможете получать уведомления, когда код клиента изменяет коллекцию. Кроме того, List<T>
предоставляет множество членов, таких как BinarySearch
, которые бесполезны или неприменимы во многих сценариях.❌ ИЗБЕГАЙТЕ использования
Hashtable
или Dictionary<TKey, TValue>
в общедоступных API. Они предназначенными для использования во внутренней реализации. Публичные API должны использовать IDictionary
, IDictionary<TKey, TValue>
или пользовательский тип, реализующий один или оба этих интерфейса.❌ ИЗБЕГАЙТЕ использования
IEnumerator<T>
, IEnumerator
или любого типа, реализующего любой из этих интерфейсов, кроме для типа возврата метода GetEnumerator
. Типы, возвращающие итераторы из методов, отличных от GetEnumerator
, нельзя использовать с оператором foreach
.❌ ИЗБЕГАЙТЕ использования обоих интерфейсов
IEnumerator<T>
и IEnumerable<T>
для одного типа. То же относится и к необобщённым интерфейсам IEnumerator
и IEnumerable
.Параметры коллекции
✅ ИСПОЛЬЗУЙТЕ наименее специализированный возможный тип в качестве типа параметра. Большинство членов, принимающих коллекции в качестве параметров, используют интерфейс
IEnumerable<T>
.❌ ИЗБЕГАЙТЕ использования
ICollection<T>
или ICollection
в качестве параметра просто для доступа к свойству Count
. Вместо этого рассмотрите возможность использования IEnumerable<T>
или IEnumerable
и динамической проверки, реализует ли объект ICollection<T>
или ICollection
.Продолжение следует...
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести восемьдесят первый. #оффтоп #dotnext
В Москве проходит конференция DotNext. Топовые докладчики и конские цены за билеты (даже просто за видео всех докладов). Но есть бесплатная трансляция из одного из залов. Вот запись вчерашнего дня. А на канале конференции есть куча видео выступлений с прошедших конференций. Эх, где бы найти недельку свободного времени.
В Москве проходит конференция DotNext. Топовые докладчики и конские цены за билеты (даже просто за видео всех докладов). Но есть бесплатная трансляция из одного из залов. Вот запись вчерашнего дня. А на канале конференции есть куча видео выступлений с прошедших конференций. Эх, где бы найти недельку свободного времени.
День двести восемьдесят второй.
Сертификат Microsoft. Шаг предпоследний
Завтра день Хэ. Записался на экзамен на 10 утра. За сегодня нужно очистить рабочий стол от... в общем от всего: дополнительные мониторы, девайсы, ручки, карандаши, книжки, листочки, часы и всё остальное в пределах доступности. Кроме того, нужно провести тест системы на скорость интернета, качество камеры и микрофона, сфотографировать себя, паспорт и пустой стол. Завтра помимо этого придётся забарикадироваться, чтобы в комнату никто не входил и не издавал громких звуков, которые наблюдающий мог бы расценить как подсказку. Да, специально обученный человек будет через вебкамеру наблюдать за мной на всём протяжении экзамена. Такие дела.
А пока вот ещё один ресурс... нет, всё-таки не для подготовки, а для того, чтобы освежить память перед экзаменом (хотя там 8 часов видео). Ребята с шутками-прибаутками обсуждают все основные моменты, так что смотрится легко. Однако видео довольно старые, поэтому частично там уже давно устаревшая информация, например, про проекты под Windows 8, но в принципе, если совсем уж нечего делать, можно посмотреть (как обычно, на английском, конечно).
https://channel9.msdn.com/Series/Programming-in-CSharp-Jump-Start
Сертификат Microsoft. Шаг предпоследний
Завтра день Хэ. Записался на экзамен на 10 утра. За сегодня нужно очистить рабочий стол от... в общем от всего: дополнительные мониторы, девайсы, ручки, карандаши, книжки, листочки, часы и всё остальное в пределах доступности. Кроме того, нужно провести тест системы на скорость интернета, качество камеры и микрофона, сфотографировать себя, паспорт и пустой стол. Завтра помимо этого придётся забарикадироваться, чтобы в комнату никто не входил и не издавал громких звуков, которые наблюдающий мог бы расценить как подсказку. Да, специально обученный человек будет через вебкамеру наблюдать за мной на всём протяжении экзамена. Такие дела.
А пока вот ещё один ресурс... нет, всё-таки не для подготовки, а для того, чтобы освежить память перед экзаменом (хотя там 8 часов видео). Ребята с шутками-прибаутками обсуждают все основные моменты, так что смотрится легко. Однако видео довольно старые, поэтому частично там уже давно устаревшая информация, например, про проекты под Windows 8, но в принципе, если совсем уж нечего делать, можно посмотреть (как обычно, на английском, конечно).
https://channel9.msdn.com/Series/Programming-in-CSharp-Jump-Start
День двести восемьдесят третий.
Сертификат Microsoft. Экзамен 70-483
УХ!!!! Это было волнительно!!!
Перед экзаменом нужно пройти тест системы. Чтобы работал интернет, микрофон, камера, направленная на тебя. Далее сфоткать себя, паспорт и рабочий стол со всех сторон. После этого к тебе подключается наблюдатель, проверяет твои данные и просит ещё раз показать комнату вокруг и рабочий стол (чтобы никого и ничего не было). Также закрыть все сторонние приложения, кроме специального, в котором будешь сдавать тест. Потом нужно прочитать (да, это стоит прочитать) и согласиться с договором о неразглашении. Ты соглашаешься, что не будешь раскрывать информацию о вопросах, не попытаешься никаким образом хакнуть систему, скачать вопросы или ещё как-нибудь сжульничать. При любом подозрении Microsoft вправе аннулировать результаты экзамена и запретить сдавать экзамены впредь. Так что о деталях вопросов не расскажу, извините.
После этого даётся опрос, не относящийся собственно к тесту (типа социология): сколько лет кодишь, сколько в C#, и (самое интересное!) как ты оцениваешь уровень своих знаний в каждой области, по которой проводится тест. Ответил честно, что тему «Отладка приложений и реализация функций безопасности» знаю плоховато. Написано было, что это не повлияет ни на вопросы, ни на результаты теста. Уж не знаю, действительно ли это так, но показалось, что именно этой темой меня больше всего в тесте и задалбывали 😊 Хотя, может быть, просто показалось.
Что касается теста. На всё даётся 2 часа времени. У меня был 41 вопрос (не знаю, возможно, количество варьируется). Вопросы действительно охватывают все перечисленные в описании экзамена темы. Кстати, насколько уж я скептически относился к предложенной в описании экзамена книге по подготовке и видеокурсу по экзамену, но пренебрегать ими точно не стоит. На несколько вопросов ответил вот ровно оттуда. Особенно это касается тем, которые редко использую в своей практике: шифрование, запись в журнал событий Windows, сериализация (я использую широко распространённый пакет Newtonsoft.Json, а там вопросы по родным майкрософтовским классам).
Во многих статьях, которые я приводил ранее, советуют отмечать вопросы для перепроверки позже. Так вот, обязательно делайте это! Если вы не отметили вопрос, больше к нему вернуться будет нельзя. Я отмечал все и перепроверял. В одном действительно нашёл ошибку из-за своей невнимательности.
Вопросы хитрые, но не то, чтобы слишком. Авторы отказались от множественных вариантов и вариантов, где ни один ответ не является верным. Думаю, это правильно. Там, где надо выбрать несколько вариантов, говорится, что их ровно 2 или ровно 3. Соответственно, можно даже логически домыслить, что вот этот ответ верный, но он не согласуется с остальными.
Что в итоге? Нужно набрать 700 баллов, причём никто не говорит, сколько стоит каждый вопрос. Я набрал 828!!! 🥳 После экзамена показывается шкала с результатами в каждой области знаний, у меня 100% в «Создании и использовании типов», в остальных поменьше (от 75 до 90). Правильных ответов или указаний, в каких вопросах ошибки, не дают. Возможно, подробная информация будет позже на сайте Microsoft (им нужно до 7 рабочих дней, чтобы обработать результат и выдать сертификат). Как только будет готово, поделюсь здесь.
Как-то так.
PS: Это вовсе не значит, что цель достигнута, «всем спасибо, все свободны»))) Я продолжу выпускать заметки и мысли на канале. А поскольку по работе занят веб-разработкой, то следующая цель – сертификат по ASP.NET MVC.
Спасибо, что читаете.
Сертификат Microsoft. Экзамен 70-483
УХ!!!! Это было волнительно!!!
Перед экзаменом нужно пройти тест системы. Чтобы работал интернет, микрофон, камера, направленная на тебя. Далее сфоткать себя, паспорт и рабочий стол со всех сторон. После этого к тебе подключается наблюдатель, проверяет твои данные и просит ещё раз показать комнату вокруг и рабочий стол (чтобы никого и ничего не было). Также закрыть все сторонние приложения, кроме специального, в котором будешь сдавать тест. Потом нужно прочитать (да, это стоит прочитать) и согласиться с договором о неразглашении. Ты соглашаешься, что не будешь раскрывать информацию о вопросах, не попытаешься никаким образом хакнуть систему, скачать вопросы или ещё как-нибудь сжульничать. При любом подозрении Microsoft вправе аннулировать результаты экзамена и запретить сдавать экзамены впредь. Так что о деталях вопросов не расскажу, извините.
После этого даётся опрос, не относящийся собственно к тесту (типа социология): сколько лет кодишь, сколько в C#, и (самое интересное!) как ты оцениваешь уровень своих знаний в каждой области, по которой проводится тест. Ответил честно, что тему «Отладка приложений и реализация функций безопасности» знаю плоховато. Написано было, что это не повлияет ни на вопросы, ни на результаты теста. Уж не знаю, действительно ли это так, но показалось, что именно этой темой меня больше всего в тесте и задалбывали 😊 Хотя, может быть, просто показалось.
Что касается теста. На всё даётся 2 часа времени. У меня был 41 вопрос (не знаю, возможно, количество варьируется). Вопросы действительно охватывают все перечисленные в описании экзамена темы. Кстати, насколько уж я скептически относился к предложенной в описании экзамена книге по подготовке и видеокурсу по экзамену, но пренебрегать ими точно не стоит. На несколько вопросов ответил вот ровно оттуда. Особенно это касается тем, которые редко использую в своей практике: шифрование, запись в журнал событий Windows, сериализация (я использую широко распространённый пакет Newtonsoft.Json, а там вопросы по родным майкрософтовским классам).
Во многих статьях, которые я приводил ранее, советуют отмечать вопросы для перепроверки позже. Так вот, обязательно делайте это! Если вы не отметили вопрос, больше к нему вернуться будет нельзя. Я отмечал все и перепроверял. В одном действительно нашёл ошибку из-за своей невнимательности.
Вопросы хитрые, но не то, чтобы слишком. Авторы отказались от множественных вариантов и вариантов, где ни один ответ не является верным. Думаю, это правильно. Там, где надо выбрать несколько вариантов, говорится, что их ровно 2 или ровно 3. Соответственно, можно даже логически домыслить, что вот этот ответ верный, но он не согласуется с остальными.
Что в итоге? Нужно набрать 700 баллов, причём никто не говорит, сколько стоит каждый вопрос. Я набрал 828!!! 🥳 После экзамена показывается шкала с результатами в каждой области знаний, у меня 100% в «Создании и использовании типов», в остальных поменьше (от 75 до 90). Правильных ответов или указаний, в каких вопросах ошибки, не дают. Возможно, подробная информация будет позже на сайте Microsoft (им нужно до 7 рабочих дней, чтобы обработать результат и выдать сертификат). Как только будет готово, поделюсь здесь.
Как-то так.
PS: Это вовсе не значит, что цель достигнута, «всем спасибо, все свободны»))) Я продолжу выпускать заметки и мысли на канале. А поскольку по работе занят веб-разработкой, то следующая цель – сертификат по ASP.NET MVC.
Спасибо, что читаете.
День двести восемьдесят четвёртый. #BestPractices
Советы по использованию общих типов
Коллекции. Продолжение
Свойства коллекции и возвращаемые значения
❌ ИЗБЕГАЙТЕ предоставления свойств-мутаторов коллекции (т.е. изменяющих коллекцию в целом). Например, пользователи могут заменить содержимое коллекции, сначала очистив её, а затем добавить новое содержимое. Если замена всей коллекции является распространенным сценарием, рассмотрите возможность предоставления метода
✅ ИСПОЛЬЗУЙТЕ
✅ ИСПОЛЬЗУЙТЕ
В случаях, когда вы уверены, что единственный сценарий, который вы когда-либо захотите поддержать, - это итерация только вперед, вы можете использовать
⚠️ РАССМОТРИТЕ использование подклассов общих базовых коллекций вместо непосредственного использования коллекций. Это позволяет выбрать осмысленное имя и добавить вспомогательные элементы, которых нет в базовых типах коллекций. Это особенно применимо к высокоуровневым API.
⚠️ РАССМОТРИТЕ возвращение подкласса
⚠️ РАССМОТРИТЕ использование коллекции с ключами, если элементы, хранящиеся в коллекции, имеют уникальные ключи (имена, идентификаторы и т. д.). Коллекции с ключами - это коллекции, которые могут индексироваться как целым числом, так и ключом, и обычно реализуются путем наследования от
❌ ИЗБЕГАЙТЕ возвращения
Снапшоты или Живые Коллекции
Коллекции, представляющие состояние в определенный момент времени, называются снапшотами (моментальными снимками). Например, коллекция, содержащая строки, возвращённые из запроса к базе данных, будет снапшотом. Коллекции, которые всегда представляют текущее состояние, называются живыми коллекциями. Например, коллекция элементов
❌ ИЗБЕГАЙТЕ возвращение снапшотов из свойств. Свойства должны возвращать живые коллекции. Акцессоры свойств должны быть очень лёгкими операциями. Для возврата снапшота необходимо создать копию внутренней коллекции в операции порядка O(n).
✅ ИСПОЛЬЗУЙТЕ снапшоты либо живые коллекции
Продолжение следует…
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
Советы по использованию общих типов
Коллекции. Продолжение
Свойства коллекции и возвращаемые значения
❌ ИЗБЕГАЙТЕ предоставления свойств-мутаторов коллекции (т.е. изменяющих коллекцию в целом). Например, пользователи могут заменить содержимое коллекции, сначала очистив её, а затем добавить новое содержимое. Если замена всей коллекции является распространенным сценарием, рассмотрите возможность предоставления метода
AddRange
.✅ ИСПОЛЬЗУЙТЕ
Collection<T>
или подкласс Collection<T>
для типов свойств или возвращаемых значений, представляющих изменяемые коллекции. Если Collection<T>
не удовлетворяет некоторым требованиям (например, коллекция не должна реализовывать IList), используйте пользовательскую коллекцию, реализуя IEnumerable<T>
, ICollection<T>
или IList<T>
.✅ ИСПОЛЬЗУЙТЕ
ReadOnlyCollection<T>
, подкласс ReadOnlyCollection<T>
или, в редких случаях, IEnumerable<T>
для типов свойств или возвращаемых значений, представляющих коллекции только для чтения. В основном отдавайте предпочтение ReadOnlyCollection<T>
, либо пользовательской коллекции (для неё реализуйте ICollection<T>.IsReadOnly
, возвращающее true
).В случаях, когда вы уверены, что единственный сценарий, который вы когда-либо захотите поддержать, - это итерация только вперед, вы можете использовать
IEnumerable<T>
.⚠️ РАССМОТРИТЕ использование подклассов общих базовых коллекций вместо непосредственного использования коллекций. Это позволяет выбрать осмысленное имя и добавить вспомогательные элементы, которых нет в базовых типах коллекций. Это особенно применимо к высокоуровневым API.
⚠️ РАССМОТРИТЕ возвращение подкласса
Collection<T>
или ReadOnlyCollection<T>
из часто используемых методов и свойств. Это позволит вам добавить вспомогательные методы или изменить реализацию коллекции в будущем.⚠️ РАССМОТРИТЕ использование коллекции с ключами, если элементы, хранящиеся в коллекции, имеют уникальные ключи (имена, идентификаторы и т. д.). Коллекции с ключами - это коллекции, которые могут индексироваться как целым числом, так и ключом, и обычно реализуются путем наследования от
KeyedCollection<TKey, TItem>
. Однако они обычно занимают больший объем памяти и не должны использоваться, если требования к памяти перевешивают преимущества наличия ключей.❌ ИЗБЕГАЙТЕ возвращения
null
из свойств коллекции или из методов, возвращающих коллекции. Вместо этого верните пустую коллекцию или пустой массив. Общее правило состоит в том, что null
и пустые коллекции или массивы должны обрабатываться одинаково.Снапшоты или Живые Коллекции
Коллекции, представляющие состояние в определенный момент времени, называются снапшотами (моментальными снимками). Например, коллекция, содержащая строки, возвращённые из запроса к базе данных, будет снапшотом. Коллекции, которые всегда представляют текущее состояние, называются живыми коллекциями. Например, коллекция элементов
ComboBox
является живой коллекцией.❌ ИЗБЕГАЙТЕ возвращение снапшотов из свойств. Свойства должны возвращать живые коллекции. Акцессоры свойств должны быть очень лёгкими операциями. Для возврата снапшота необходимо создать копию внутренней коллекции в операции порядка O(n).
✅ ИСПОЛЬЗУЙТЕ снапшоты либо живые коллекции
IEnumerable<T>
для представления коллекций, которые являются нестабильными (то есть могут изменяться без явного изменения коллекции). В общем, все коллекции, представляющие общий ресурс (например, файлы в каталоге), являются нестабильными. Такие коллекции очень трудно или невозможно реализовать как живые коллекции, если только вы не реализуете однонаправленный итератор.Продолжение следует…
Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести восемьдесят пятый. #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.