День пятый.
Подписался на курсы ITVDN по С#/.Net разработке. Куча видеоуроков и, самое главное, практические домашние задания для закрепления материала. Посмотрим, что из этого выйдет. Стартовые и базовые курсы по C# мне уже, конечно, не интересны, а вот более продвинутые попробую.
Примечание: все ссылки на материалы, которые я привожу, опробованы исключительно на личном опыте и не являются рекламой, если только об этом явно не написано.
Подписался на курсы ITVDN по С#/.Net разработке. Куча видеоуроков и, самое главное, практические домашние задания для закрепления материала. Посмотрим, что из этого выйдет. Стартовые и базовые курсы по C# мне уже, конечно, не интересны, а вот более продвинутые попробую.
Примечание: все ссылки на материалы, которые я привожу, опробованы исключительно на личном опыте и не являются рекламой, если только об этом явно не написано.
👍3
А пока поделюсь с вами книгой, которая, по моему личному мнению, абсолютный “маст рид” для разработчика приложений. Именно для разработчика, а не для труЪ программиста, который не считается труЪ, если не вызубрил Кнута. Ну а для обитателей грешной земли незаменимым руководством по разработке является “Совершенный код” Стива МакКоннелла. Сам перечитывал её несколько раз, а также посмотрел курс лекций самого Стива на https://construx.vueocity.com Решил освежить в памяти основные моменты, поэтому буду выкладывать периодически конспекты с лекций.
0. Введение
Основной концепцией создания программного обеспечения является концепция “Защитного программирования”. Точно так же, как вы смотрите по сторонам при переходе дороги, даже на зелёный свет, в создании ПО есть несколько принципов, которые помогут вам создавать качественный код с минимумом ошибок. Основные принципы:
1. Управление сложностью
2. Именование
3. Процесс программирования псевдокодом
4. Утверждения
5. Отладка
6. Оптимизация кода
7. Обработка ошибок
8. Предвидение изменений
В следующих постах разберу каждый принцип подробнее.
#CodeComplete
0. Введение
Основной концепцией создания программного обеспечения является концепция “Защитного программирования”. Точно так же, как вы смотрите по сторонам при переходе дороги, даже на зелёный свет, в создании ПО есть несколько принципов, которые помогут вам создавать качественный код с минимумом ошибок. Основные принципы:
1. Управление сложностью
2. Именование
3. Процесс программирования псевдокодом
4. Утверждения
5. Отладка
6. Оптимизация кода
7. Обработка ошибок
8. Предвидение изменений
В следующих постах разберу каждый принцип подробнее.
#CodeComplete
👍5
День шестой. #оффтоп
Недавно наткнулся в YouTube на прекрасный канал про программирование вообще и C# в частности ExtremeCode. https://www.youtube.com/channel/UCBNlINWfd08qgDkUTaUY4_w
Более полусотни видео как для начинающих (плейлист “C# для маленьких и тупых”), так и для продвинутых разработчиков. Рассказывается невероятно интересно с обилием мемчиков и шуточек-прибауточек (осторожно, 18+). Так что я после просмотра первого видео, появившегося в моей ленте, зашёл к ним и залип на целый день. К сожалению, у ребят давно не выходило новых роликов. Не знаю, с чем это связано, надеюсь, они найдут потерянное вдохновение и продолжат радовать интересным и полезным контентом.
Повторюсь ещё раз, это не реклама, а личный опыт.
Недавно наткнулся в YouTube на прекрасный канал про программирование вообще и C# в частности ExtremeCode. https://www.youtube.com/channel/UCBNlINWfd08qgDkUTaUY4_w
Более полусотни видео как для начинающих (плейлист “C# для маленьких и тупых”), так и для продвинутых разработчиков. Рассказывается невероятно интересно с обилием мемчиков и шуточек-прибауточек (осторожно, 18+). Так что я после просмотра первого видео, появившегося в моей ленте, зашёл к ним и залип на целый день. К сожалению, у ребят давно не выходило новых роликов. Не знаю, с чем это связано, надеюсь, они найдут потерянное вдохновение и продолжат радовать интересным и полезным контентом.
Повторюсь ещё раз, это не реклама, а личный опыт.
👍5
День седьмой. #ЗаметкиНаПолях
C# давно поддерживает два оператора проверки типа объекта:
Небезопасное приведение типов
Вам часто приходится приводить объект к другому типу. Вы можете сделать это напрямую, используя оператор приведения, например,
Если вы абсолютно уверены в типе объекта, вы можете использовать небезопасное приведение типа, которое работает немного быстрее. Но мы же хотим избежать ошибок.
Безопасное приведение типа с помощью is
Первый способ безопасного приведения – проверка типа с помощью
• Нет различий между
• Метод не работает с необнуляемыми (non-nullable) типами, такими как
Новый метод безопасного приведения типов в C# 7 состоит в использовании сопоставления с шаблоном. Вот пример, как безопасно привести
*Источник: https://www.danielcrabtree.com/blog/152/c-sharp-7-is-operator-patterns-you-wont-need-as-as-often
C# давно поддерживает два оператора проверки типа объекта:
is
и as
. С приведением типов в C# есть несколько проблем. Небезопасное приведение типов
Вам часто приходится приводить объект к другому типу. Вы можете сделать это напрямую, используя оператор приведения, например,
(string)input
. Но что, если input
не строка? Вы получите исключение.Если вы абсолютно уверены в типе объекта, вы можете использовать небезопасное приведение типа, которое работает немного быстрее. Но мы же хотим избежать ошибок.
Безопасное приведение типа с помощью is
Первый способ безопасного приведения – проверка типа с помощью
is
, а затем приведение. Проблема в том, что к объекту приходится обращаться дважды.if(input is string)Безопасное приведение типа с помощью
{
string text = (string)input;
}
as
«Более лучшим» способом будет использование оператора as
, который возвращает null
, когда input
не строка. Это позволяет не обращаться к объекту дважды, слегка выигрывая в производительности.string text = input as string;Но здесь есть два ограничения:
if(text != null)
{
...
}
• Нет различий между
null
и неверным типом• Метод не работает с необнуляемыми (non-nullable) типами, такими как
int
Безопасное приведение типов с помощью is
и сопоставлением с шаблономНовый метод безопасного приведения типов в C# 7 состоит в использовании сопоставления с шаблоном. Вот пример, как безопасно привести
input
к строке:if(input is string text)Этот метод не только предоставляет самый короткий и ясный синтаксис, но и избегает всех перечисленных выше проблем.
{
...
}
*Источник: https://www.danielcrabtree.com/blog/152/c-sharp-7-is-operator-patterns-you-wont-need-as-as-often
👍7
День восьмой.
Свойства.
Нужны ли в языке программирования свойства или нужно оставаться в контексте «труЪ ООП», объявляя методы
*Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 10.
Свойства.
Нужны ли в языке программирования свойства или нужно оставаться в контексте «труЪ ООП», объявляя методы
getXXX
и setXXX
? Спор, наверное, такой же древний, как вражда остроконечников с тупоконечниками. И смысла в нём примерно столько же. Как всегда, всё зависит от стандартов написания кода в вашей компании. Лично я, в отличие от всё того же Рихтера, не вижу никаких причин для заблуждений и непонимания при использовании свойств. Если код, реализующий свойство, не нарушает абстракции, то, на мой взгляд блокPerson p = new Person();выглядит гораздо понятнее, чем
p.FirstName = “Jon”;
p.LastName = “Smith”;
p.Age = 40;
Console.WriteLine(“{0} {1}, {2}”, p.FirstName, p.LastName, p.Age);
Person p = new Person();Не говоря уже об упрощённом синтаксисе инициализации свойств:
p.setFirstName(“Jon”);
p.setLastName(“Smith”);
p.setAge(40);
Console.WriteLine(“{0} {1}, {2}”, p.getFirstName(), p.getLastName(), p.getAge());
Person p = new Person { FirstName = “Jon”, LastName = “Smith”, Age = 40 };Привыкнуть к синтаксису можно очень быстро, а для элементарных случаев код класса значительно сокращается, когда нет необходимости писать однотипные методы доступа.
*Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 10.
👍2
День девятый. #CodeComplete
1. Управление сложностью. Начало
Управление сложностью - самая важная задача при создании программного обеспечения. Два главных принципа управления сложностью:
1. Управляйте существенной сложностью (сложностью реальной проблемы). Например, делите программу на части, причём таким образом, чтобы работая над одной частью, можно было легко игнорировать другие части.
2. Избегайте случайной сложности (добавляемой в программу вами).
Приёмы проектирования для управления сложностью:
1. Иерархии
2. Сокрытие информации
3. Модуляризация
4. Инкапсуляция
5. Абстракция
6. Связность
7. Разделение ответственности
Важно: Пробуйте БОЛЕЕ ОДНОГО варианта проектирования. Не спешите реализовывать первый вариант, пришедший в голову.
1. Иерархии.
Иерархии – это естественный способ организации сложной информации. Используйте иерархии в ПО: многоуровневая информационная структура, иерархии модулей, иерархии классов.
2. Сокрытие информации
Цель: скрывайте сложность
Процедура:
- перечислите проектные решения, которые скорее всего будут изменены
- разработайте модули так, чтобы скрыть эти проектные решения
- разработайте интерфейсы модулей так, чтобы они не зависели от возможных изменений в модулях
Важно: Не жертвуйте удобством чтения кода во имя удобства его написания! Код читается гораздо чаще, чем пишется.
3. Модуляризация
Модуляризация основана на сокрытии информации.
Модули должны быть хорошо спроектированными чёрными ящиками, которые легко могут быть заменены.
4. Абстракция
Абстракция – это не то же самое, что инкапсуляция.
Абстракция позволяет вам смотреть на сложную информационную структуру в упрощённом виде. Хорошо спроектированный объект представляет из себя идеальную абстракцию (объект реального мира). У него есть только свойства и методы объекта реального мира и никаких других.
Абстракция – мощный инструмент управления сложностью.
Продолжение следует…
1. Управление сложностью. Начало
Управление сложностью - самая важная задача при создании программного обеспечения. Два главных принципа управления сложностью:
1. Управляйте существенной сложностью (сложностью реальной проблемы). Например, делите программу на части, причём таким образом, чтобы работая над одной частью, можно было легко игнорировать другие части.
2. Избегайте случайной сложности (добавляемой в программу вами).
Приёмы проектирования для управления сложностью:
1. Иерархии
2. Сокрытие информации
3. Модуляризация
4. Инкапсуляция
5. Абстракция
6. Связность
7. Разделение ответственности
Важно: Пробуйте БОЛЕЕ ОДНОГО варианта проектирования. Не спешите реализовывать первый вариант, пришедший в голову.
1. Иерархии.
Иерархии – это естественный способ организации сложной информации. Используйте иерархии в ПО: многоуровневая информационная структура, иерархии модулей, иерархии классов.
2. Сокрытие информации
Цель: скрывайте сложность
Процедура:
- перечислите проектные решения, которые скорее всего будут изменены
- разработайте модули так, чтобы скрыть эти проектные решения
- разработайте интерфейсы модулей так, чтобы они не зависели от возможных изменений в модулях
Важно: Не жертвуйте удобством чтения кода во имя удобства его написания! Код читается гораздо чаще, чем пишется.
3. Модуляризация
Модуляризация основана на сокрытии информации.
Модули должны быть хорошо спроектированными чёрными ящиками, которые легко могут быть заменены.
4. Абстракция
Абстракция – это не то же самое, что инкапсуляция.
Абстракция позволяет вам смотреть на сложную информационную структуру в упрощённом виде. Хорошо спроектированный объект представляет из себя идеальную абстракцию (объект реального мира). У него есть только свойства и методы объекта реального мира и никаких других.
Абстракция – мощный инструмент управления сложностью.
Продолжение следует…
👍3
День десятый. #ITVDN
Смотрю курс C# Essential от ITVDN. Это базовый (не совсем начальный) курс по языку. Информация, конечно, знакома, но раз его предлагают «в пакете», то не грех повторить. Иногда бывает, что даже в известных темах всплывают какие-нибудь нюансы, которых раньше не знал. Что сказать. Теорией не перегружают, короткие слайды с определением понятий и основными свойствами и принципами, а потом примеры, примеры и ещё раз примеры. Разжёвывается всё до состояния «пюре для начала прикорма». Это, наверное, хорошо. Вопросов по теме после просмотра видео-урока оставаться практически не должно. Другое дело, что осиливать видео-уроки по 2-3 часа длиной сложно даже на скорости в 2.5х (если сделать ещё быстрее, то уже сложно разбирать слова). Не знаю, с какой целью видео сделаны настолько затянутыми. Может, чтобы написать, что в курсе аж 333 часа лекций. Реально же материал даже с подробным объяснением можно укладывать в, как минимум, половину времени. Кроме того, объяснение часто далеко от идеала. Даже мне, человеку знакомому с принципами ООП, иногда трудно следить за сутью из примеров, типа
Смотрю курс C# Essential от ITVDN. Это базовый (не совсем начальный) курс по языку. Информация, конечно, знакома, но раз его предлагают «в пакете», то не грех повторить. Иногда бывает, что даже в известных темах всплывают какие-нибудь нюансы, которых раньше не знал. Что сказать. Теорией не перегружают, короткие слайды с определением понятий и основными свойствами и принципами, а потом примеры, примеры и ещё раз примеры. Разжёвывается всё до состояния «пюре для начала прикорма». Это, наверное, хорошо. Вопросов по теме после просмотра видео-урока оставаться практически не должно. Другое дело, что осиливать видео-уроки по 2-3 часа длиной сложно даже на скорости в 2.5х (если сделать ещё быстрее, то уже сложно разбирать слова). Не знаю, с какой целью видео сделаны настолько затянутыми. Может, чтобы написать, что в курсе аж 333 часа лекций. Реально же материал даже с подробным объяснением можно укладывать в, как минимум, половину времени. Кроме того, объяснение часто далеко от идеала. Даже мне, человеку знакомому с принципами ООП, иногда трудно следить за сутью из примеров, типа
abstract class AbstractClassЧто мешало придумать для примеров объекты реального мира, решительно непонятно:
{
public void Method();
}
class ConcreteClassA : AbstractClass
{
…
}
class ConcreteClassB : AbstractClass
{
…
}
abstract class Animal
{
public void Go();
}
class Cat : Animal
{
…
}
class Dog : Animal
{
…
}
👍4
День одиннадцатый. #ЗаметкиНаПолях
События.
С самого начала работы с формами ещё на Delphi, мне всегда было интересно, что это за магические параметры у вызова события нажатия на кнопку:
Паттерн состоит в следующем:
- наблюдатели подписываются на рассылку, передавая объекту делегат метода обратного вызова
- объект при возникновении нового события вызывает этот метод у всех подписанных наблюдателей, передавая в него «сообщение» - класс, наследуемый от
Рассмотрим, реализацию этого паттерна на С#:
1. Определяем тип сообщения, например, письмо:
3. В объекте наблюдения определяем метод, уведомляющий о событии:
6. В основной программе:
События.
С самого начала работы с формами ещё на Delphi, мне всегда было интересно, что это за магические параметры у вызова события нажатия на кнопку:
OnClick(Object sender, EventArgs e);На самом деле это реализация паттерна проектирования «Наблюдатель». Если коротко, то у нас есть объект наблюдения (допустим система сообщений), и есть «наблюдатели», например, различные сервисы отправки сообщений: факс, смс, e-mail и т.п.
Паттерн состоит в следующем:
- наблюдатели подписываются на рассылку, передавая объекту делегат метода обратного вызова
- объект при возникновении нового события вызывает этот метод у всех подписанных наблюдателей, передавая в него «сообщение» - класс, наследуемый от
EventArgs
(e
) и ссылку на себя (sender
).Рассмотрим, реализацию этого паттерна на С#:
1. Определяем тип сообщения, например, письмо:
class NewMailEventArgs : EventArgs {2. В объекте наблюдения определяем член-событие:
public string From {get; set;}
public string To {get; set;}
public string Message {get; set;}
}
class MailManager {Здесь обобщённый делегат
public event EventHandler<NewMailEventArgs> NewMail;
…
}
System.EventHandler
принимает тип нашего сообщения. Значит наблюдатели должны предоставить метод обратного вызова, прототип которого совпадает с делегатом. Например:void Method(Object sender, NewMailEventArgs e);Объект наблюдения ответственен за создание объекта-сообщения и вызов метода обратного вызова с передачей ему ссылки на себя (
Object sender
) и сообщения (NewMailEventArgs e
).3. В объекте наблюдения определяем метод, уведомляющий о событии:
class MailManager {4. В объекте наблюдения определяем метод, вызывающий событие:
…
//уведомляем о событии
private void OnNewMail(NewMailEventArgs e) {
EventHandler<NewMailEventArgs> temp = NewMail;
if(temp != null) temp(this, e);
}
…
}
class MailManager {5. Определяем наблюдателя:
…
public void SimulateNewMail(…) {
…
//создаём сообщение
var msg = new NewMailEventArgs{From=“…”, To=“…”, Message=“…”};
//вызываем метод, уведомляющий о событии
OnNewMail(msg);
}
}
class Fax {C# допускает упрощённый синтаксис подписки и отписки
//храним ссылку на объект наблюдения
private MailManager mailMgr;
//передаём в конструктор ссылку на объект наблюдения
public Fax(MailManager mm) {
mailMgr = mm;
}
// метод обратного вызова
private void FaxMsg(Object sender, NewMailEventArgs e) {
…
// обрабатываем сообщение e (отправляем факс)
…
}
// подписываемся на уведомления (можно сразу в конструкторе)
public void Register() {
mailMgr.NewMail += FaxMsg;
}
// отписываемся от уведомлений
public void Unregister() {
mailMgr.NewMail -= FaxMsg;
}
}
mailMgr.NewMail += FaxMsg;На самом деле в объекте наблюдения хранится список наблюдателей. Оператор += вызывает метод, добавляющий наблюдателя в список, а -=, соответственно, метод, удаляющий из списка.
mailMgr.NewMail -= FaxMsg;
6. В основной программе:
//создаём объект наблюденияИсточник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 11.
MailManager mailMgr = new MailManager();
…
//создаём наблюдателя и подписываем его
Fax fax = new Fax(mailMgr);
fax.Register();
…
//возникновение события
mailMgr.SimulateNewMail(…);
👍4
День двенадцатый. #CodeComplete
1. Управление сложностью. Окончание
5. Инкапсуляция
Инкапсуляция – это не то же самое, что абстракция.
- Инкапсуляция не позволяет вам смотреть на упрощённую информационную структуру в усложнённом виде.
- Скрывайте детали за хорошо спроектированным интерфейсом, чтобы избежать программирования «сквозь» интерфейс (использовать класс, зная о деталях его реализации).
- Сосредоточьте своё внимание на интерфейсах. Реализация интерфейса воздействует только на качество кода. Качество интерфейса воздействует на срок жизни, расширяемость, масштабируемость и т.п. программного обеспечения в целом.
6. Связность
- Каждый метод/класс должен решать РОВНО ОДНУ задачу!
- Сложность создания ясного имени для метода или класса часто тревожный знак плохой его связности. Это не проблема именования, это проблема дизайна.
7. Разделение ответственности
- Основная идея – «Разделяй и властвуй»
- Пытайтесь разделять программу на сферы ответственности
- Разделение ответственности применяется к более высоким уровням проектирования, например, разделению на подсистемы (см. картинку ниже).
- Часто разделение невыполнимо из-за синтаксиса языка.
1. Управление сложностью. Окончание
5. Инкапсуляция
Инкапсуляция – это не то же самое, что абстракция.
- Инкапсуляция не позволяет вам смотреть на упрощённую информационную структуру в усложнённом виде.
- Скрывайте детали за хорошо спроектированным интерфейсом, чтобы избежать программирования «сквозь» интерфейс (использовать класс, зная о деталях его реализации).
- Сосредоточьте своё внимание на интерфейсах. Реализация интерфейса воздействует только на качество кода. Качество интерфейса воздействует на срок жизни, расширяемость, масштабируемость и т.п. программного обеспечения в целом.
6. Связность
- Каждый метод/класс должен решать РОВНО ОДНУ задачу!
- Сложность создания ясного имени для метода или класса часто тревожный знак плохой его связности. Это не проблема именования, это проблема дизайна.
7. Разделение ответственности
- Основная идея – «Разделяй и властвуй»
- Пытайтесь разделять программу на сферы ответственности
- Разделение ответственности применяется к более высоким уровням проектирования, например, разделению на подсистемы (см. картинку ниже).
- Часто разделение невыполнимо из-за синтаксиса языка.
День тринадцатый. #Оффтоп
Научиться чему-либо невозможно без практики. Наткнулся вот на интересный сервис https://exercism.io (только на английском языке). Там представлены упражнения для закрепления материала на множестве языков, в том числе C#. Начиная с «Hello, world!» и до достаточно сложных. В каждом языке можно выбрать курс с «ментором», который будет просматривать и оценивать (одобрять или не одобрять) ваши решения и давать комментарии (кстати, удивительно, что менторы дают действительно нужные комментарии, всегда корректно и по делу). Пока ментор не одобрит ваше решение, переходить к следующему упражнению основного курса нельзя. Но в то же время можно порешать множество сторонних задач, которые не будут оцениваться ментором, достаточно решить задачу и выложить код на всеобщее обозрение.
Ну а если уж дожидаться оценок не охота, можно проходить курс самостоятельно, хотя это не рекомендуется.
Интересный момент, что все упражнения построены по принципу разработки через тестирование (TDD). Вы скачиваете проект с юнит-тестами. Все они, естественно не проходят. Ваша задача решить проблему так, чтобы все тесты проходили. То есть правильность решения можно проверять и самостоятельно.
Интересно также и смотреть и решения других людей. Их можно оценивать и комментировать. Даже для вполне тривиальных задач решения попадаются просто гениальные. Лично я для себя отмечаю абсолютно взрывающие мозг решения через LINQ. Народ ужимает 30+ строк обычного кода до одной строки даже там, где это, казалось бы, невозможно. Понимаю для себя, что этот момент надо подтягивать.
Научиться чему-либо невозможно без практики. Наткнулся вот на интересный сервис https://exercism.io (только на английском языке). Там представлены упражнения для закрепления материала на множестве языков, в том числе C#. Начиная с «Hello, world!» и до достаточно сложных. В каждом языке можно выбрать курс с «ментором», который будет просматривать и оценивать (одобрять или не одобрять) ваши решения и давать комментарии (кстати, удивительно, что менторы дают действительно нужные комментарии, всегда корректно и по делу). Пока ментор не одобрит ваше решение, переходить к следующему упражнению основного курса нельзя. Но в то же время можно порешать множество сторонних задач, которые не будут оцениваться ментором, достаточно решить задачу и выложить код на всеобщее обозрение.
Ну а если уж дожидаться оценок не охота, можно проходить курс самостоятельно, хотя это не рекомендуется.
Интересный момент, что все упражнения построены по принципу разработки через тестирование (TDD). Вы скачиваете проект с юнит-тестами. Все они, естественно не проходят. Ваша задача решить проблему так, чтобы все тесты проходили. То есть правильность решения можно проверять и самостоятельно.
Интересно также и смотреть и решения других людей. Их можно оценивать и комментировать. Даже для вполне тривиальных задач решения попадаются просто гениальные. Лично я для себя отмечаю абсолютно взрывающие мозг решения через LINQ. Народ ужимает 30+ строк обычного кода до одной строки даже там, где это, казалось бы, невозможно. Понимаю для себя, что этот момент надо подтягивать.
Exercism
Learn, practice and get world-class mentoring in over 50 languages. 100% free.
День четырнадцатый. #ЗаметкиНаПолях
Конструкторы типов
CLR помимо конструкторов экземпляров поддерживает конструкторы типов (также известные как статические конструкторы, конструкторы классов или инициализаторы типов). Они служат для установки первоначального состояния типа. У типа может быть только один конструктор без параметров. Формат конструктора типа:
Для инициализации статических полей лучше использовать встроенный синтаксис инициализации, потому что CLR может оптимизировать типы, не имеющие явно определённых статических конструкторов. То есть лучше использовать:
- для инициализации объектов-одиночек (паттерн Singleton)
- когда класс использует запись в лог
- при создании оболочек для неуправляемого кода, когда конструктор типа используется для вызова метода
При возникновении необработанного исключения в конструкторе типа CLR больше не вызывает конструктор типа, а считает такой тип непригодным в текущем домене приложения. При попытке обратиться к любому члену этого типа будет выброшено исключение
Поэтому не рекомендуется использовать следующий пример из книги Рихтера:
Иногда конструктор типа используется для обобщённого типа, чтобы аргументы типа соответствовали определённым критериям. Например, обобщённый тип, используемый только с перечислимыми типами:
Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Главы 8, 12.
- https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
Конструкторы типов
CLR помимо конструкторов экземпляров поддерживает конструкторы типов (также известные как статические конструкторы, конструкторы классов или инициализаторы типов). Они служат для установки первоначального состояния типа. У типа может быть только один конструктор без параметров. Формат конструктора типа:
class SomeClass {Поток, начавший выполнение конструктора типа, получает исключающую блокировку, что гарантирует, что конструктор типа вызовется только один раз.
static SomeClass() {
//исполняется при первом обращении к типу
}
}
Для инициализации статических полей лучше использовать встроенный синтаксис инициализации, потому что CLR может оптимизировать типы, не имеющие явно определённых статических конструкторов. То есть лучше использовать:
class SomeClass {вместо
private static int x = 5;
}
class SomeClass {Конструкторы типов применяются:
private static int x;
static SomeClass() {
x = 5;
}
}
- для инициализации объектов-одиночек (паттерн Singleton)
- когда класс использует запись в лог
- при создании оболочек для неуправляемого кода, когда конструктор типа используется для вызова метода
LoadLibrary
.При возникновении необработанного исключения в конструкторе типа CLR больше не вызывает конструктор типа, а считает такой тип непригодным в текущем домене приложения. При попытке обратиться к любому члену этого типа будет выброшено исключение
System.TypeInitializationException
.Поэтому не рекомендуется использовать следующий пример из книги Рихтера:
Иногда конструктор типа используется для обобщённого типа, чтобы аргументы типа соответствовали определённым критериям. Например, обобщённый тип, используемый только с перечислимыми типами:
public class GenericTypeRequiresEnum<T> {Вместо этого лучше использовать конструкцию
static GenericTypeRequiresEnum() {
if (!typeof(T).IsEnum)
throw new ArgumentException("T должно быть перечислимым типом");
}
}
where
:public class GenericTypeRequiresEnum<T> where T : EnumОна позволяет проверять принадлежность
{
…
}
T
к определённому типу на этапе компиляции (см. скриншот ниже). Однако, поддержка перечислимых типов (Enum
) в конструкции where
появилась только в C# версии 7.3.Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Главы 8, 12.
- https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
.NET Разработчик pinned «Hello, world! В этих ваших интернетах всякие тренеры личностного роста и прочие спецы по мотивации говорят, что бороться с прокрастинацией и не бросать начатое проще, если хотя бы записываешь прогресс в дневник. А ещё лучше, если делишься им с друзьями. Я…»
День пятнадцатый. #CodeComplete
2. Именование
1. Имена переменных
Обычно имена переменных, которые недостаточно конкретны, чтобы быть использованы только для одной цели в процедуре, это плохие имена.
- Имя переменной должно быть существительным, описывающим реальную сущность
- Не используйте префиксы, обозначающие тип переменной или отделяющие поля класса от локальных переменных (“
- Делайте имена переменным настолько конкретными, насколько это возможно
- Чем очевиднее, тем лучше
- Чем ближе имя к сущности реального мира, тем обычно оно более полезно
2. Именование методов
- Описывайте в имени всё, что делает метод (либо разбейте его на несколько)
- Делайте имена настолько длинными, насколько можно
- Бессмысленные или неопределённые глаголы (
- Приближайте имена к необходимому уровню абстракции, чтобы скрыть детали реализации метода
- Делайте имена методов настолько высокоуровневыми (близкими бизнес-логике или к реальному миру), насколько это возможно
3. Соглашения об именовании
- утвердите соглашение о согласованном наименовании стандартных операций, например,
- избегайте ненужных вариаций: сокращения, непонятные аббревиатуры, смесь языков и т.п. (
2. Именование
1. Имена переменных
Обычно имена переменных, которые недостаточно конкретны, чтобы быть использованы только для одной цели в процедуре, это плохие имена.
- Имя переменной должно быть существительным, описывающим реальную сущность
- Не используйте префиксы, обозначающие тип переменной или отделяющие поля класса от локальных переменных (“
__...
”, “m_...
”, “s_...
”, “i_...
” и т.п.)- Делайте имена переменным настолько конкретными, насколько это возможно
- Чем очевиднее, тем лучше
- Чем ближе имя к сущности реального мира, тем обычно оно более полезно
2. Именование методов
- Описывайте в имени всё, что делает метод (либо разбейте его на несколько)
- Делайте имена настолько длинными, насколько можно
- Бессмысленные или неопределённые глаголы (
Calc
, HandleClass
, ProcessInput
и т.п.) – тревожный знак- Приближайте имена к необходимому уровню абстракции, чтобы скрыть детали реализации метода
- Делайте имена методов настолько высокоуровневыми (близкими бизнес-логике или к реальному миру), насколько это возможно
3. Соглашения об именовании
- утвердите соглашение о согласованном наименовании стандартных операций, например,
user.GetID()
или user.ID.Get()
- то же касается стандартных аббревиатур и языковых вариаций (color
/colour
)- избегайте ненужных вариаций: сокращения, непонятные аббревиатуры, смесь языков и т.п. (
totalCount
/ttlCnt
/itog
, firstName
/fName
/firstNm
/FN
/imya
).День шестнадцатый. #ЗаметкиНаПолях
Использование using
Все мы привыкли к использованию ключевого слова
Директива
1. Наиболее распространённый вариант использования уже упоминался выше. Нет необходимости каждый раз писать полное имя типа с пространством имён, например:
Оператор using упрощает работу с объектами которые реализуют интерфейс
Использование using
Все мы привыкли к использованию ключевого слова
using
в начале наших файлов для упрощения обращения к типам в определённом пространстве имён. Но у него есть и другие интересные варианты использования.Директива
1. Наиболее распространённый вариант использования уже упоминался выше. Нет необходимости каждый раз писать полное имя типа с пространством имён, например:
using System.Text;2. Для упрощённого обращения к статическим методам класса можно использовать
…
var sb = new StringBuilder();
using static
, например:using static System.Console;3. Использование псевдонимов (алиасов) для пространств имён или типов. Например, для упрощения использования обобщённых типов (в самой директиве, правда, все имена придётся написать полностью):
using static System.Math;
…
WriteLine(Sqrt(3*3 + 4*4));
using System;Оператор
using DateTimeList = System.Collections.Generic.List<System.DateTime>;
…
var dtl = new DateTimeList {DateTime.MinValue, DateTime.Now, DateTime.MaxValue};
Оператор using упрощает работу с объектами которые реализуют интерфейс
IDisposable
. Интерфейс имеет один метод Dispose()
, который используется для освобождения ресурсов, использованных объектом. При использовании using
не обязательно явно вызывать Dispose()
для объекта.using (SqlConnection conn = new SqlConnection()) {При этом компилятор сгенерирует приблизительно следующий код:
…
}
SqlConnection conn = new SqlConnection();
try {
…
}
finally {
if (conn != null)
((IDisposable)conn).Dispose();
}
👍2
День семнадцатый. #Оффтоп
Перевёл статью для канала CodeBlog “Топ-7 вещей необходимых разработчику ПО”. Немного добавлю от себя. Мне изначально понравился подход автора, который не стал углубляться в банальности, типа, «вам надо изучить алгоритмы» или «вы обязательно должны знать, как работать с указателями», или, что особенно доставляло в вузе, «изучение программирования хорошо бы начинать с ассемблера, а потом переходить к высокоуровневым языкам» (WTF???)
В статье же упор делается на условия работы. Как наиболее эффективно использовать доступные вам инструменты, чтобы не только быстро и качественно делать свою работу, но и получать от неё удовольствие. Про себя могу отметить, что попадаю почти под все пункты :) Хотя, пришёл к этому далеко не сразу. Удобство хорошего кресла и просторного рабочего стола я оценил всего лишь года три назад, когда захотели дома сделать спальню из моего кабинета, а меня выселили в другую комнату. Я заодно прикупил себе и кресло с большим компьютерным уголком. А начинал я работу, сидя буквально на обычном деревянном стуле за старым советским столом-книжкой (олды должны помнить такие), который к тому же ещё и ходил ходуном, если на него облокотиться. Идею двух мониторов тоже подсмотрел у коллег, которые ими активно пользовались. Хотя поначалу у меня одним монитором был экран ноута, а вторым старый 15-дюймовый монитор 4:3 с максимальным разрешением 1024х768.
Должен отметить, что мне откровенно повезло с работодателем. И железо, и софт постоянно обновляются по инициативе работодателя. На данный момент мой рабочий ноутбук – это 4х-ядерный Intel Core i7, 16Gb оперативной памяти и 2 SSD диска на 1Tb и 2Tb и 2 монитора по 24”. Вы не представляете, как быстро привыкаешь к хорошему! Когда я прихожу к знакомым помочь с компьютером, я часто ловлю себя на том, что запускаю 3 или 4 окна браузера сразу. Просто потому, что тыкаю на ярлык, и ничего не происходит. На моём ноуте это значит, что я просто промахнулся или не нажал кнопку мыши, поэтому я на автомате тыкаю ещё раз, и ещё раз. А оказывается, просто компу нужно время, чтобы запустить чёртов браузер!
Почитал комментарии в контакте под статьёй. Конечно, там попеняли на то, что хрен ты чего от наших работодателей добьёшься. Да, согласен. Но здесь остаётся только посочувствовать и пожелать налегать на последний пункт статьи - книги и сертификаты - и доказывать, что вы этого достойны. Хороших всем работодателей, интересных задач, а главное, получайте удовольствие от работы, ведь для этого вы и выбрали карьеру программиста, не так ли?
https://shwanoff.ru/top-7-things-a-software-developer-needs/
Перевёл статью для канала CodeBlog “Топ-7 вещей необходимых разработчику ПО”. Немного добавлю от себя. Мне изначально понравился подход автора, который не стал углубляться в банальности, типа, «вам надо изучить алгоритмы» или «вы обязательно должны знать, как работать с указателями», или, что особенно доставляло в вузе, «изучение программирования хорошо бы начинать с ассемблера, а потом переходить к высокоуровневым языкам» (WTF???)
В статье же упор делается на условия работы. Как наиболее эффективно использовать доступные вам инструменты, чтобы не только быстро и качественно делать свою работу, но и получать от неё удовольствие. Про себя могу отметить, что попадаю почти под все пункты :) Хотя, пришёл к этому далеко не сразу. Удобство хорошего кресла и просторного рабочего стола я оценил всего лишь года три назад, когда захотели дома сделать спальню из моего кабинета, а меня выселили в другую комнату. Я заодно прикупил себе и кресло с большим компьютерным уголком. А начинал я работу, сидя буквально на обычном деревянном стуле за старым советским столом-книжкой (олды должны помнить такие), который к тому же ещё и ходил ходуном, если на него облокотиться. Идею двух мониторов тоже подсмотрел у коллег, которые ими активно пользовались. Хотя поначалу у меня одним монитором был экран ноута, а вторым старый 15-дюймовый монитор 4:3 с максимальным разрешением 1024х768.
Должен отметить, что мне откровенно повезло с работодателем. И железо, и софт постоянно обновляются по инициативе работодателя. На данный момент мой рабочий ноутбук – это 4х-ядерный Intel Core i7, 16Gb оперативной памяти и 2 SSD диска на 1Tb и 2Tb и 2 монитора по 24”. Вы не представляете, как быстро привыкаешь к хорошему! Когда я прихожу к знакомым помочь с компьютером, я часто ловлю себя на том, что запускаю 3 или 4 окна браузера сразу. Просто потому, что тыкаю на ярлык, и ничего не происходит. На моём ноуте это значит, что я просто промахнулся или не нажал кнопку мыши, поэтому я на автомате тыкаю ещё раз, и ещё раз. А оказывается, просто компу нужно время, чтобы запустить чёртов браузер!
Почитал комментарии в контакте под статьёй. Конечно, там попеняли на то, что хрен ты чего от наших работодателей добьёшься. Да, согласен. Но здесь остаётся только посочувствовать и пожелать налегать на последний пункт статьи - книги и сертификаты - и доказывать, что вы этого достойны. Хороших всем работодателей, интересных задач, а главное, получайте удовольствие от работы, ведь для этого вы и выбрали карьеру программиста, не так ли?
https://shwanoff.ru/top-7-things-a-software-developer-needs/
👍5
День восемнадцатый. #CodeComplete
3. Процесс Программирования с Псевдокодом
При проектировании сложных или объёмных методов сложно написать метод от начала до конца из головы. В этих случаях помогает процесс программирования с псевдокодом. Он состоит из нескольких этапов:
1. Напишите, что должен делать каждый блок кода на естественном языке, используя комментарии (это будет псевдокод).
Комментарии должны быть на достаточно высоком уровне, чтобы не дублировать то, что будет написано в коде, а объяснять, что делает блок кода. Например, вместо:
используйте
3. Напишите код каждого блока под каждым блоком комментариев.
Применяйте ППП рекурсивно, если нужно. Например, если блок написан слишком общими словами, которые сложно сразу перевести в код, примените ППП к этому блоку (рассмотрите возможность вынести этот блок в отдельный метод).
4. Оставьте псевдокод в виде комментариев.
Преимущества ППП:
- Упрощает изначальное написание кода
- Упрощает обзор кода
- Приводит к лучше организованному коду
- Автоматизирует процесс добавления комментариев
- Упрощает возвращение к работе, если вас прервали на середине
- Сокращает количество ошибок, поскольку процесс позволяет (вынуждает) вас больше думать о правильном проектировании метода
3. Процесс Программирования с Псевдокодом
При проектировании сложных или объёмных методов сложно написать метод от начала до конца из головы. В этих случаях помогает процесс программирования с псевдокодом. Он состоит из нескольких этапов:
1. Напишите, что должен делать каждый блок кода на естественном языке, используя комментарии (это будет псевдокод).
Комментарии должны быть на достаточно высоком уровне, чтобы не дублировать то, что будет написано в коде, а объяснять, что делает блок кода. Например, вместо:
// для каждого i меньше длины массива objectArr
используйте
// перебираем все объекты массива в цикле2. Проверьте весь псевдокод метода. Добавьте более детальные комментарии там, где это необходимо.
3. Напишите код каждого блока под каждым блоком комментариев.
Применяйте ППП рекурсивно, если нужно. Например, если блок написан слишком общими словами, которые сложно сразу перевести в код, примените ППП к этому блоку (рассмотрите возможность вынести этот блок в отдельный метод).
4. Оставьте псевдокод в виде комментариев.
Преимущества ППП:
- Упрощает изначальное написание кода
- Упрощает обзор кода
- Приводит к лучше организованному коду
- Автоматизирует процесс добавления комментариев
- Упрощает возвращение к работе, если вас прервали на середине
- Сокращает количество ошибок, поскольку процесс позволяет (вынуждает) вас больше думать о правильном проектировании метода
👍2
День девятнадцатый. #ЗаметкиНаПолях
Обобщения
Обобщения – это механизм многократного использования алгоритма. Разработчик описывает алгоритм, но не указывает типы данных, с которыми тот работает. Применяя алгоритм, другой разработчик должен указать конкретные типы данных. Например, обобщённый список определяется как List<T>. Здесь переменная T, указывающая на тип называется параметром типа. В объявлении обобщённого типа её можно использовать в любом месте, где указывается, тип данных. Например:
- в параметре метода
Microsoft рекомендует называть параметры типа
Преимущества обобщений:
- защита исходного кода: для использования обобщённого алгоритма не нужен доступ к исходному тексту алгоритма;
- безопасность типов: компилятор и CLR обеспечивают, чтобы в алгоритме использовались лишь объекты, совместимые с указанным типом данных;
- более простой и понятный код: из-за того, что компилятор обеспечивает безопасность типов уже на этапе компиляции, требуется меньше операций приведения типов, а такой код проще писать и поддерживать;
- повышение производительности: не требуется лишних операций приведения типов, для структур не требуется упаковки/разупаковки, что ускоряет работу кода.
Наиболее частым видом использования обобщённых типов являются коллекции, такие как связанные списки, хэш-таблицы, стеки, очереди, деревья и т.п. Операции, вроде добавления и удаления элементов коллекции, выполняются примерно одинаково вне зависимости от типа хранимых данных. В большинстве случаев, когда требуется класс коллекции, рекомендуется использовать классы, определённые в библиотеке классов .NET.
При создании ваших собственных обобщённых типов, важно учитывать следующие моменты:
1. Какие типы обобщать в параметры типа. Обычно, чем больше типов вы параметризуете, тем более гибким становится ваш код. Но слишком обобщённый тип может привести к коду, который будет трудно читать и понять другим разработчикам.
2. Какие ограничения, если они нужны, применить к параметрам типа (об ограничениях в следующих постах). Хорошим тоном будет применить максимально возможные ограничения, которые всё равно позволят вам использовать требуемые типы. Например, если обобщённый тип подразумевает использование только ссылочных типов, добавьте ограничение
3. Обдумайте обобщённое поведение в базовом классе и подклассах.
4. Нужно ли реализовать один или больше обобщённых интерфейсов. Например, если вы разрабатываете класс, который будет использоваться в качестве элемента обобщённой коллекции, вам может потребоваться реализовать интерфейс вроде
Продолжение следует…
Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 12.
- https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/generics/index
Обобщения
Обобщения – это механизм многократного использования алгоритма. Разработчик описывает алгоритм, но не указывает типы данных, с которыми тот работает. Применяя алгоритм, другой разработчик должен указать конкретные типы данных. Например, обобщённый список определяется как List<T>. Здесь переменная T, указывающая на тип называется параметром типа. В объявлении обобщённого типа её можно использовать в любом месте, где указывается, тип данных. Например:
- в параметре метода
public void Add(T item);
- в возвращаемом значенииpublic T[] ToArray();
public T this[int index] { get; set; }
- при определении локальных переменных и полей внутри классаMicrosoft рекомендует называть параметры типа
T
или словом, начинающимся с T
(TKey
, TResult
). При этом рекомендуется использовать значимые имена, где это возможно или если параметр типа ограничен конкретным классом или интерфейсом (например, параметр типа, ограниченный интерфейсом ISession
, может быть назван TSession
).Преимущества обобщений:
- защита исходного кода: для использования обобщённого алгоритма не нужен доступ к исходному тексту алгоритма;
- безопасность типов: компилятор и CLR обеспечивают, чтобы в алгоритме использовались лишь объекты, совместимые с указанным типом данных;
- более простой и понятный код: из-за того, что компилятор обеспечивает безопасность типов уже на этапе компиляции, требуется меньше операций приведения типов, а такой код проще писать и поддерживать;
- повышение производительности: не требуется лишних операций приведения типов, для структур не требуется упаковки/разупаковки, что ускоряет работу кода.
Наиболее частым видом использования обобщённых типов являются коллекции, такие как связанные списки, хэш-таблицы, стеки, очереди, деревья и т.п. Операции, вроде добавления и удаления элементов коллекции, выполняются примерно одинаково вне зависимости от типа хранимых данных. В большинстве случаев, когда требуется класс коллекции, рекомендуется использовать классы, определённые в библиотеке классов .NET.
При создании ваших собственных обобщённых типов, важно учитывать следующие моменты:
1. Какие типы обобщать в параметры типа. Обычно, чем больше типов вы параметризуете, тем более гибким становится ваш код. Но слишком обобщённый тип может привести к коду, который будет трудно читать и понять другим разработчикам.
2. Какие ограничения, если они нужны, применить к параметрам типа (об ограничениях в следующих постах). Хорошим тоном будет применить максимально возможные ограничения, которые всё равно позволят вам использовать требуемые типы. Например, если обобщённый тип подразумевает использование только ссылочных типов, добавьте ограничение
class
. Это не допустит использования вашего типа со структурами.3. Обдумайте обобщённое поведение в базовом классе и подклассах.
4. Нужно ли реализовать один или больше обобщённых интерфейсов. Например, если вы разрабатываете класс, который будет использоваться в качестве элемента обобщённой коллекции, вам может потребоваться реализовать интерфейс вроде
IComparable<T>
, где T
– это тип вашего класса.Продолжение следует…
Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 12.
- https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/generics/index
👍3
День двадцатый. #Оффтоп
Stackoverflow
Наверное, самый известный из используемых мной ресурсов. Захожу туда почти ежедневно и не по разу, чуть реже, чем в гугл. То есть, строго говоря, 9 из 10 вопросов к гуглу по программированию ведут на stackoverflow.com (английский естественно). Уже лет 15 как решил для себя, что поиск ответа с гораздо большей вероятностью приведёт к желаемому результату, если вопрос задан пусть даже на ломаном английском, нежели на русском. И тут нет ничего странного. Англоговорящее (и даже ломано-англоговорящее) сообщество гораздо обширнее русскоговорящего (хотя русскоязычная версия сайта тоже есть - ru.stackoverflow.com). Но все попытки поискать информацию по-русски меня почему-то зачастую вели на малознакомые и странноватые форумы, да и там часто только задавался мой вопрос, а ответа на него не было.
Стараюсь вспомнить случаи, когда решения какого-нибудь вопроса или разновидности решения не было на stackoverflow, и вспоминаю за все эти годы от силы случаев 10. При этом в основном это были узкоспециализированные вопросы по нюансам работы какой-нибудь специфической библиотеки или плагина, вроде jQuery Datatables.
Одно время я даже пытался заработать там немного рейтинга, отвечая на вопросы, но это невероятно сложно, потому что там настоящая гонка. Вопрос не успевает появиться, и уже через минуту-другую под ним 2-3 ответа или комментария. Так что в принципе, даже задав там вопрос, ответа долго ждать не пришлось бы. Но я так и не добрался пока до того, чтобы что-то спросить. Причина – см. предыдущий абзац :)
Stackoverflow
Наверное, самый известный из используемых мной ресурсов. Захожу туда почти ежедневно и не по разу, чуть реже, чем в гугл. То есть, строго говоря, 9 из 10 вопросов к гуглу по программированию ведут на stackoverflow.com (английский естественно). Уже лет 15 как решил для себя, что поиск ответа с гораздо большей вероятностью приведёт к желаемому результату, если вопрос задан пусть даже на ломаном английском, нежели на русском. И тут нет ничего странного. Англоговорящее (и даже ломано-англоговорящее) сообщество гораздо обширнее русскоговорящего (хотя русскоязычная версия сайта тоже есть - ru.stackoverflow.com). Но все попытки поискать информацию по-русски меня почему-то зачастую вели на малознакомые и странноватые форумы, да и там часто только задавался мой вопрос, а ответа на него не было.
Стараюсь вспомнить случаи, когда решения какого-нибудь вопроса или разновидности решения не было на stackoverflow, и вспоминаю за все эти годы от силы случаев 10. При этом в основном это были узкоспециализированные вопросы по нюансам работы какой-нибудь специфической библиотеки или плагина, вроде jQuery Datatables.
Одно время я даже пытался заработать там немного рейтинга, отвечая на вопросы, но это невероятно сложно, потому что там настоящая гонка. Вопрос не успевает появиться, и уже через минуту-другую под ним 2-3 ответа или комментария. Так что в принципе, даже задав там вопрос, ответа долго ждать не пришлось бы. Но я так и не добрался пока до того, чтобы что-то спросить. Причина – см. предыдущий абзац :)
День двадцать первый. #ЗаметкиНаПолях
Ограничения обобщений
Ограничения сообщают компилятору, какими характеристиками должен обладать параметр типа. Без ограничений параметр типа может быть любым. Если клиентский код попытается использовать ваш класс с типом, который не совместим с ограничением, возникнет ошибка компиляции. Синтаксис:
Неограниченные параметры типа
Параметры типа, не имеющие ограничений, называются неограниченными. К ним применяются следующие правила:
- операторы
- они могут быть приведены к типу
- вы можете сравнивать их с
Зачем использовать ограничения
Ограничивая параметр типа, вы увеличиваете количество доступных операций и вызовов методов теми, которые поддерживаются типом-ограничением и всеми типами в его иерархии наследования. Неограниченные параметры типа поддерживают только простейшие операции и методы, определённые в
При применении ограничения
Ограничения нескольких параметров
Вы можете применить ограничения к нескольким параметрам, и несколько ограничений к одному параметру. Cами ограничения могут быть обобщёнными типами:
Позволяет указать, что между указанными аргументами типа должны быть определённые отношения:
Источник: https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters
Ограничения обобщений
Ограничения сообщают компилятору, какими характеристиками должен обладать параметр типа. Без ограничений параметр типа может быть любым. Если клиентский код попытается использовать ваш класс с типом, который не совместим с ограничением, возникнет ошибка компиляции. Синтаксис:
public class SomeList<T> where T : BaseClassТипы ограничений:
{
…
}
T : struct
– значимый тип (структура);T : class
– ссылочный тип: класс, интерфейс, делегат (C#7.3+) или массив;T : new()
– аргумент типа должен иметь конструктор без параметров; T : <имя класса>
- аргумент типа должен быть этого класса или наследником класса;T : <имя интерфейса>
- аргумент типа должен быть этим интерфейсом или классом, реализующим этот интерфейс (можно добавлять несколько ограничений интерфейса, тогда аргумент типа должен реализовывать все интерфейсы);T : TBase
– параметры типа T
и TBase
такие, что T
должен быть типом TBase
или наследовать от него;T : unmanaged
(C#7.3+) – не ссылочный тип и не имеет членов ссылочного типа на всех уровнях наследования (значимые примитивные типы, указатели, перечисления или структуры, определённые пользователем). Неограниченные параметры типа
Параметры типа, не имеющие ограничений, называются неограниченными. К ним применяются следующие правила:
- операторы
!=
и ==
не могут быть использованы, поскольку нет гарантии, что конкретные аргументы типа их поддерживают;- они могут быть приведены к типу
System.Object
или явно к любому интерфейсному типу;- вы можете сравнивать их с
null
(значимые типы при этом всегда возвратят false
).Зачем использовать ограничения
Ограничивая параметр типа, вы увеличиваете количество доступных операций и вызовов методов теми, которые поддерживаются типом-ограничением и всеми типами в его иерархии наследования. Неограниченные параметры типа поддерживают только простейшие операции и методы, определённые в
System.Object
.При применении ограничения
where T : class
избегайте использования операторов ==
и !=
к параметру типа, поскольку эти операторы проверяют только идентичность ссылки, а не значения. Для проверки по значению используйте ограничения where T : IEquatable<T>
или where T : IComparable<T>
и реализуйте эти интерфейсы в классах, которые будут использоваться в обобщённом классе. Ограничения нескольких параметров
Вы можете применить ограничения к нескольким параметрам, и несколько ограничений к одному параметру. Cами ограничения могут быть обобщёнными типами:
class Base { }Параметры типа как ограничения
class Test<T, U>
where U : struct
where T : Base, System.IComparable<T>, new()
{ }
Позволяет указать, что между указанными аргументами типа должны быть определённые отношения:
private static List<TBase> ConvertList<T, TBase>(IList<T> list) where T : TBaseЗдесь параметр
{
// преобразование списка T в список TBase
…
}
T
ограничен параметром TBase
. То есть аргумент, заданный для T
, должен быть совместим с аргументом, заданным для TBase
.Источник: https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters
👍1