Pull to refresh

Comments 37

При перечислении объектов для вызова следует использовать оператор yield return, а не создавать возвращающую коллекцию.

"В зависимости от ситуации" явно пропущено.

В оригинале данной вставки нет, но замечание справедливое. Спасибо.

Пункт 2 — сомнителен. Активное использование ленивых вычислений (а yield return — это ленивые вычисления) может привести к тому, что исключение произойдет совсем не там где оно ожидалось.


yield return сам по себе — лучше чем создание коллекции только чтобы ее вернуть — но бросаться переписывать уже готовую программу не следует. Могут быть сюрпризы.


По пункту 4 — забыли рассказать что делать если исключение нужно сохранить, а потом бросать заново уже в другом месте. А нужно сохранять не исключение, а ExceptionDispatchInfo. На новых фреймворках.


В старых фреймворках можно вызвать у исключения метод InternalPreserveStackTrace через рефлексию. То есть, конечно же, не напрямую, а создав делегат.


По пункту 8. Так в чем ошибка или ловушка-то заключаются? Это же очевидное ожидаемое поведение...

он рендерит бесполезный класс
На экран, что ли, рендерит? :) Правильно: делает класс бесполезным. Учите английский.

Хотелось как лучше, а получилось как всегда XD.
Исправлено, спасибо.

Спасибо за статью. Хоть многие пункты кажутся мне очевидными, про 7 я не знал. :)
Т.е. компилятор выбирает более специфический строковый метод при втором вызове.

И что здесь не так?
Универсальный метод — для вообще всех данных.
А не универсальный — для обработки с конкретными типами.

Ловушка в чем? В том, что мы сделали метод для строки и он вызывается… для строк?
А какого поведения здесь ждет программист?

Когда знаешь как работают generic, понимаешь, что компилятор еще один метод с той же сигнатурой не создаст.


А когда для тебя это магическая функция, принимающая что угодно...

Я просто не понимаю, какое альтернативное поведение может здесь ждать программист.

Что у тебя две функции и обе принимают string.

и по какому принципу по мнению этого программиста компилятор выбирает какую функцию использовать?

Вот тут и ловушка. Это ж магическое программирование. В зависимости от ситуации.

Какая магия? Все завист от типы ссылки. Здесь не больше магии, чем в перекрытых методах.

Вы мне объясняете, как дженерики работают? Я знаю. Я объясняю, где тут может быть проблема в восприятии

Проблема в восприятии может быть с чем угодно, стоит только зафиксировать уровень читателя на определенном уровне. Для программиста, который хотя бы универ закончил (не говоря уже про год+ практической работы) это совсем не магия. А таких — большая часть и читателей хабра, и разработчиков в принципе.

Есть целые фирмы, где работают StackOverflow-программисты. Если вы с такими не сталкивались никогда, вам повезло.
Пятый пункт интересный. Становится понятно зачем нужен инициализатор типа)
в том смысле что объявленные в классе поля все равно успевают инициализироваться, несмотря на то что конструктор не отрабатывает
Кто-нибудь знает, почему сравнение Value-Types медленное? Почему нельзя построить сравнивающий Expression Tree при первом вызове сравнения структур данного типа и закешировать его?
Почему нельзя построить сравнивающий Expression Tree при первом вызове сравнения структур данного типа и закешировать его?

А зачем? Если у вас в value type есть ссылочные поля, логика Equals, скорее всего, прикладная, а в этом случае вам все равно надо писать свою реализацию.


А сравнение value types, состоящих из value types — быстрое.

ValueType.Equals будет использовать отражение

Рефлексия.
Там написано в самом верху
Данная статья переведена с помощью средств машинного перевода.

Принято, исправлю.
Спасибо.

Я видел этот термин и в книгах, переведенных на русский язык человечьим переводом.

Скажите это гуртовщикам мыши.
Оба термина широко-употребимы и все их понимают, слух не режет вроде.

Мне режет, потому что каждый раз представляю себе зеркало. Есть два адекватных варианта перевода: рефлексия и интроспекция.

«отражение» почти никогда не слышал в этом смысле

10 пункт странный. Если структуры нужно сравнивать, то в любом случае нужно реализовывать IEquitable<T>, а рассуждать, что метод в 10 раз медленнее лучше, чем в 100 раз медленнее особого смысла нет.


А во-вторых, вот нужно мне стрингу засунуть в структуру, которую я хочу сравнивать — автор по факту говорит мне, что структуру в таком случае использовать нельзя :) Хотя все решается тривиально. По сути фреймворк просто зря имеет Equals и GetHashCode в object'е. С другой стороны, я понимаю, зачем это сделано — тут начинаются возня с мониторами, локами, сохранением состояния блокировки в хэше объекта и прочие прелести… То есть есть причины, почему все это в object'е хранится. Но по сути все кастомные структуры со сравнением обязаны реализовывать IEquitable<T>. Можно хоть roslyn-анализатор ставить, чтобы Equals вызывался исключительно интерфейсный, а не object'овый.

Лучше roslyn-генератор, чтобы дописывал нормальную реализацию :)

Это типичный АОП, стоит вспомнить те же выводимые конструкторы из Rust. Всё к этому идет, смысла писать каждый раз бойлерплейт код никакого нет.

Ещё не сказано, что обычно В структурах для скорости хэш считается только по первому полю.

1, 5, 6, 8 и 9 справедливы и для Java. Всё же несильно языки различаются =)

Номер 8 на мой взгляд, очень странный. Как раз частичная специализация шаблонов — это очень сильная фича при правильном использвоании. В качестве примера можно посмотреть у Александреску

Частичной специализации шаблона в C# нет. Номер 8 — это простая перегрузка метода.

Неоднозначность может проявляться вот в таких случаях:


public static void ExecuteTest<TValue>(TValue value)
{
     GenericTest.Test(value);
}

public static void Foo()
{
     ExecuteTest(123); // Generic method
     ExecuteTest("123"); // Generic method - все же поняли, что это не С++?
}
Sign up to leave a comment.

Articles