C#. Программирование для профессионалов

Джон Скит

Язык С# 4 стал мощнее и выразительнее, чем в прежних версиях. Воспользовавшись обобщенными типами, лямбда-выражениями, динамическим вводом, LINQ, блоками итераторов и другими средствами, вы сможете сделать удивительные вещи, но сначала следует глубже изучить сам язык С#.

Второе издание этой книги полностью пересмотрено и обновлено, здесь рассматриваются новые возможности языка С# 4, а также такие средства, как Code Contracts. Вы изучите нюансы программирования на С# на практике, узнаете, как работать с высокоуровневыми средствами, которые будете рады иметь в своем инструментарии. Книга поможет читателям избежать скрытых недостатков языка С# и ознакомиться с его «внутренними» проблемами.

Особенности книги:

  • Новые возможности языка С# 4;
  • Вспомогательные средства языка С#;
  • Советы и практический опыт.

Читатели этой книги должны быть хорошо знакомы с основами языка С# и готовы к изучению хорошего материала!

Издательство: Вильямс, 2-е издание, 2011 г.

ISBN 978-5-8459-1555-9, 978-1-9351-8247-4

Количество страниц: 544.

Содержание книги «C#. Программирование для профессионалов»:

  • 15 Предисловие
  • 19 Об авторе
  • 20 Введение
  • 25 Часть I. Отправляемся в путь
  • 27 Глава 1. Изменение способа разработки на C#
    • 28 1.1. Начнем с простого типа данных
      • 28 1.1.1. Тип Product в C# 1
      • 29 1.1.2. Строго типизированные коллекции в C# 2
      • 30 1.1.3. Автоматически реализуемые свойства в C# 3
      • 31 1.1.4. Именованные аргументы в C# 4
    • 33 1.2. Сортировка и фильтрация
      • 33 1.2.1. Сортировка продуктов по названию
      • 35 1.2.2. Запрос коллекций
    • 37 1.3. Обработка отсутствия данных
      • 37 1.3.1. Представление неизвестной цены
      • 38 1.3.2. Необязательные параметры и значения по умолчанию
    • 39 1.4. Введение в LINQ
      • 39 1.4.1. Выражения запросов и внутренние запросы
      • 40 1.4.2. Запросы XML
      • 41 1.4.3. Язык LINQ to SQL
    • 42 1.5. Модель COM и динамическая типизация
      • 42 1.5.1. Упрощение совместимости с COM
      • 43 1.5.2. Взаимодействие с динамическим языком
    • 44 1.6. Разделение платформы .NET
      • 44 1.6.1. Язык C#
      • 45 1.6.2. Среда исполнения
      • 45 1.6.3. Библиотеки инфраструктуры
    • 46 1.7. Как сделать ваш код потрясающим
      • 46 1.7.1. Представление целых программ как фрагментов
      • 47 1.7.2. Дидактический код — это не рабочий код
      • 48 1.7.3. Ваш новый лучший друг: спецификация языка
    • 48 1.8. Резюме
  • 49 Глава 2. Язык С# 1 — основа основ
    • 50 2.1. Делегаты
      • 50 2.1.1 Рецепт для простых делегатов
      • 55 2.1.2. Объединение и удаление делегатов
      • 56 2.1.3. Кратко о событиях
      • 57 2.1.4. Резюме по делегатам
    • 57 2.2. Характеристики системы типов
      • 58 2.2.1. Место языка C# в мире систем типов
      • 61 2.2.2. Когда система типов C# 1 недостаточно богата
      • 63 2.2.3. Резюме по характеристикам системы типов
    • 64 2.3. Типы значений и ссылочные типы
      • 64 2.3.1 Значения и ссылки в реальном мире
      • 65 2.3.2. Основные принципы ссылочных типов и типов значений
      • 66 2.3.3. Разрушение мифов
      • 68 2.3.4. Упаковка и распаковка
      • 69 2.3.5. Резюме по типам значений и ссылочным типам
    • 70 2.4. Вне C# 1: новые возможности на солидной базе
      • 70 2.4.1. Средства, связанные с делегатами
      • 72 2.4.2. Средства, связанные с системой типов
      • 74 2.4.3. Средства, связанные с типами значений
    • 75 2.5. Резюме
  • 77 Часть II. Язык C# 2: решение проблем языка C# 1
  • 79 Глава 3. Параметрическая типизация с обобщениями
    • 80 3.1. Почему необходимы обобщения
    • 81 3.2. Простые обобщения для повседневного использования
      • 82 3.2.1. Обучение на примере: обобщенный словарь
      • 83 3.2.2. Обобщенные типы и параметры типа
      • 86 3.2.3. Обобщенные методы и чтение объявлений обобщений
    • 90 3.3. Дополнительные сведения
      • 90 3.3.1. Ограничения типов
      • 95 3.3.2. Выведение типов для аргументов типа обобщенных методов
      • 96 3.3.3. Реализация обобщений
    • 102 3.4. Расширенные обобщения
      • 102 3.4.1. Статические поля и статические конструкторы
      • 104 3.4.2. Как компилятор JIT обрабатывает обобщения
      • 106 3.4.3. Перебор обобщений
      • 108 3.4.4. Рефлексия и обобщения
    • 112 3.5. Ограничения, налагаемые на обобщения в C# и других языках
      • 112 3.5.1. Недостаток обобщенной вариантности
      • 117 3.5.2. Недостаток ограничений оператора или «числового» ограничения
      • 119 3.5.3. Недостаток обобщенных свойств, индексаторов и других элементов типа
      • 119 3.5.4. Сравнение с шаблонами C++
      • 120 3.5.5. Сравнение с обобщениями в языке Java
    • 122 3.6. Резюме
  • 123 Глава 4. Типы, допускающие значения null
    • 123 4.1. Что вы делаете, когда у вас просто нет значения
      • 124 4.1.1. Почему переменные типа значений не могут содержать значение null
      • 125 4.1.2. Шаблоны для представления значений null в языке C# 1
    • 127 4.2. Типы System.Nullable<T> и System.Nullable
      • 127 4.2.1. Введение в тип Nullable<T>
      • 130 4.2.2. Упаковка и распаковка типа Nullable<T>
      • 131 4.2.3. Равенство экземпляров Nullable<T>
      • 132 4.2.4. Поддержка необобщенного класса Nullable
    • 133 4.3. Синтаксис языка C# 2 для типов, допускающих значения null
      • 133 4.3.1. Модификатор ?
      • 134 4.3.2. Присвоение и сравнение со значением null
      • 136 4.3.3. Преобразования и операторы типов, допускающих значения null
      • 139 4.3.4. Логика типов, допускающих значения null
      • 141 4.3.5. Использование оператора as с типами, допускающими значения null
      • 141 4.3.6. Объединяющий null-оператор
    • 144 4.4. Новые способы использования типов, допускающих значения null
      • 144 4.4.1. Попытка работы без использования выходных параметров
      • 146 4.4.2. Облегченные сравнения с использованием объединяющего null-оператора
    • 149 4.5. Резюме
  • 151 Глава 5. Скоростные делегаты
    • 152 5.1. Попрощайтесь с неуклюжим синтаксисом делегата
    • 153 5.2. Преобразования группы методов
    • 155 5.3. Ковариация и контрвариация
      • 155 5.3.1. Контрвариация для параметров делегата
      • 157 5.3.2. Ковариация типов возвращаемого значения делегата
      • 158 5.3.3. Небольшой риск несовместимости
    • 159 5.4. Встраиваемые действия делегата с анонимными методами
      • 159 5.4.1. Начнем с простого: действие с параметром
      • 161 5.4.2. Возвращение значений из анонимных методов
      • 163 5.4.3. Игнорирование параметров делегата
    • 164 5.5. Захват переменных в анонимных методах
      • 165 5.5.1. Определение замкнутых выражений и переменных различных типов
      • 166 5.5.2. Исследование поведения захваченных переменных
      • 167 5.5.3. В чем смысл захваченных переменных
      • 168 5.5.4. Продление существования захваченных переменных
      • 169 5.5.5. Создание экземпляра локальной переменной
      • 171 5.5.6. Комбинация совместно используемых и независимых переменных
      • 173 5.5.7. Правила захвата переменных и резюме
    • 174 5.6. Резюме
  • 175 Глава 6. Простой путь реализации итераторов
    • 176 6.1. C# 1: сложность самодельных итераторов
    • 179 6.2. C# 2: простые итераторы с операторами yield
      • 179 6.2.1. Блоки итератора и yield return
      • 181 6.2.2. Визуализация рабочего потока итератора
      • 183 6.2.3. Расширенный поток выполнения итератора
      • 186 6.2.4. Причуды реализации
    • 187 6.3. Реальные примеры итератора
      • 187 6.3.1. Перебор дат в расписании
      • 188 6.3.2. Перебор строк в файле
      • 191 6.3.3. Фильтрация элементов при «ленивом» использовании блока итератора и предиката
    • 193 6.4. Псевдосинхронный код и библиотека параллельных вычислений и координации
    • 195 6.5. Резюме
  • 197 Глава 7. Заключение C# 2: финальные средства
    • 198 7.1. Разделяемые типы
      • 199 7.1.1. Создание типа в нескольких файлах
      • 201 7.1.2. Использование разделяемых типов
      • 202 7.1.3. Разделяемые методы — только C# 3!
    • 204 7.2. Статические классы
    • 206 7.3. Разные степени доступа методов получения и установки значения свойства
    • 207 7.4. Псевдонимы пространства имен
      • 208 7.4.1. Квалификация псевдонимов пространства имен
      • 209 7.4.2. Глобальный псевдоним пространства имен
      • 210 7.4.3. Внешние псевдонимы
    • 211 7.5. Директивы pragma
      • 211 7.5.1. Директива pragma warning
      • 212 7.5.2. Директива pragma checksum
    • 213 7.6. Буферы фиксированного размера в небезопасном коде
    • 215 7.7. Демонстрация внутренних членов избранным сборкам
      • 215 7.7.1. Дружественные сборки в простом случае
      • 216 7.7.2. Зачем использовать атрибут InternalsVisibleTo
      • 217 7.7.3. Атрибут InternalsVisibleTo и подписанные сборки
    • 217 7.8. Резюме
  • 219 Часть III. Язык C# 3: революция в программировании
  • 221 Глава 8. Интеллектуальный компилятор
    • 222 8.1. Автоматически реализованные свойства
    • 224 8.2. Неявная типизация локальных переменных
      • 224 8.2.1. Использование ключевого слова var для объявления локальной переменной
      • 226 8.2.2. Ограничения неявной типизации
      • 227 8.2.3. Преимущества и недостатки неявной типизации
      • 228 8.2.4. Рекомендации
    • 229 8.3. Упрощенная инициализация
      • 229 8.3.1. Определение демонстрационных типов
      • 230 8.3.2. Установка простых свойств
      • 231 8.3.3. Установка свойств внедренных объектов
      • 232 8.3.4. Инициализаторы коллекции
      • 235 8.3.5. Использование средств инициализации
    • 236 8.4. Неявно типизированные массивы
    • 237 8.5. Анонимные типы
      • 237 8.5.1. Первая встреча с анонимными типами
      • 239 8.5.2. Члены анонимных типов
      • 240 8.5.3. Инициализатор проекции
      • 241 8.5.4. Какой в этом смысл?
    • 242 8.6. Резюме
  • 243 Глава 9. Лямбда-выражения и деревья выражений
    • 244 9.1. Лямбда-выражения как делегаты
      • 245 9.1.1. Предварительный выбор: представление типа делегата Func<...>
      • 245 9.1.2. Первое преобразование в лямбда-выражение
      • 247 9.1.3. Использование одиночного выражения как тела
      • 247 9.1.4. Неявно типизированные списки параметров
      • 247 9.1.5. Сокращение для одиночного параметра
    • 249 9.2. Простой пример использования типа List<T> и событий
      • 249 9.2.1. Фильтрация, сортировка и действия со списками
      • 251 9.2.2. Регистрация в обработчике событий
    • 252 9.3. Деревья выражений
      • 252 9.3.1. Программное построение деревьев выражений
      • 253 9.3.2. Компиляция деревьев выражений в делегаты
      • 255 9.3.3. Преобразование лямбда-выражений C# в деревья выражений
      • 258 9.3.4. Деревья выражений — основа LINQ
      • 259 9.3.5. Деревья выражений вне LINQ
    • 261 9.4. Изменения в механизме выведения типов и разрешения перегрузки
      • 261 9.4.1. Причины изменений: упрощение вызова обобщенных методов
      • 262 9.4.2. Выведение типа возвращаемого значения анонимных функций
      • 264 9.4.3. Двухэтапное выведение типов
      • 267 9.4.4. Выбор правильной версии перегруженного метода
      • 269 9.4.5. Оболочка выведения типов и разрешения перегрузки
    • 269 9.5. Резюме
  • 271 Глава 10. Методы расширения
    • 272 10.1. Жизнь до методов расширения
    • 274 10.2. Синтаксис метода расширения
      • 274 10.2.1. Объявление методов расширения
      • 275 10.2.2. Вызов методов расширения
      • 277 10.2.3. Поиск метода расширения
      • 278 10.2.4. Вызов метода по пустой ссылке
    • 279 10.3. Методы расширения в .NET 3.5
      • 280 10.3.1. Первые шаги с классом Enumerable
      • 281 10.3.2. Фильтрация при помощи метода Where и сцепления вызовов методов
      • 283 10.3.3. Интерлюдия: разве мы не видели метод Where прежде?
      • 284 10.3.4. Проецирование с использованием метода Select и анонимных типов
      • 285 10.3.5. Сортировка с использованием метода OrderBy
      • 286 10.3.6. Бизнес-примеры с использованием сцепления
    • 287 10.4. Идеи и правила применения
      • 288 10.4.1. «Расширение мира» и обогащение интерфейсов
      • 288 10.4.2. Текучие интерфейсы
      • 290 10.4.3. Разумное использование методов расширения
    • 291 10.5. Резюме
  • 293 Глава 11. Выражения запросов и LINQ to Objects
    • 294 11.1. Введение в LINQ
      • 294 11.1.1. Фундаментальные концепции LINQ
      • 299 11.1.2. Определение эталонной модели данных
    • 300 11.2. Сначала простое: выбор элементов
      • 300 11.2.1. Начнем с источника и закончим выбором
      • 301 11.2.2. Трансляция компилятора как основа выражений запроса
      • 304 11.2.3. Переменные диапазона и нетривиальные проекции
      • 305 11.2.4. Операторы Cast, OfType и явно типизированные переменные диапазона
    • 307 11.3. Фильтрация и упорядочение последовательности
      • 308 11.3.1. Фильтрация с использованием директивы where
      • 308 11.3.2. Вырожденное выражение запроса
      • 309 11.3.3. Упорядочение с использованием директивы orderby
    • 311 11.4. Директива let и прозрачные идентификаторы
      • 311 11.4.1. Промежуточное вычисление с директивой let
      • 312 11.4.2. Прозрачные идентификаторы
    • 314 11.5. Объединения
      • 314 11.5.1. Внутренние объединения с использованием директивы join
      • 318 11.5.2. Групповое объединение и директива join...into
      • 321 11.5.3. Перекрестное объединение и сглаживание последовательности с использованием нескольких директив from
    • 324 11.6. Группировки и продолжения
      • 324 11.6.1. Группировка при помощи директивы group...by
      • 327 11.6.2. Продолжения запроса
    • 330 11.7. Выбор между выражениями запроса и точечной формой записи
      • 330 11.7.1. Операции, требующие точечной формы записи
      • 331 11.7.2. Выражения запроса, где точечная форма записи может оказаться проще
      • 331 11.7.3. В каких случаях выбирать выражения запроса
    • 332 11.8. Резюме
  • 335 Глава 12. LINQ вне коллекций
    • 336 12.1. Запрос к базе данных при помощи LINQ to SQL
      • 336 12.1.1. Первые шаги: база данных и модель
      • 338 12.1.2. Исходные запросы
      • 341 12.1.3. Запросы, задействующие объединения
    • 343 12.2. Преобразования с использованием интерфейсов IQueryable и IQueryProvider
      • 343 12.2.1. Знакомство с интерфейсом IQueryable<T> и связанными интерфейсами
      • 345 12.2.2. Имитация: реализация интерфейса для регистрации вызовов
      • 347 12.2.3. Склеивание выражений: методы расширения класса Queryable
      • 349 12.2.4. Имитационный провайдер запроса в действии
      • 350 12.2.5. Оболочка IQueryable
    • 351 12.3. Дружественные API LINQ и LINQ to XML
      • 351 12.3.1. Базовые типы в LINQ to XML
      • 353 12.3.2. Декларативное создание
      • 355 12.3.3. Запросы одиночных узлов
      • 357 12.3.4. Сглаженные операторы запроса
      • 358 12.3.5. Работа в гармонии с LINQ
    • 359 12.4. Замена LINQ to Objects на Parallel LINQ
      • 359 12.4.1. Рисование множества Мандельброта в одном потоке
      • 361 12.4.2. Знакомство с ParallelEnumerable, ParallelQuery и AsParallel
      • 362 12.4.3. Настройка параллельных запросов
    • 364 12.5. Инверсия модели запросов при помощи LINQ to Rx
      • 364 12.5.1. Интерфейсы IObservable<T> и IObserver<T>
      • 366 12.5.2. Начнем с простого (снова)
      • 367 12.5.3. Запрос Observables
      • 369 12.5.4. В чем смысл
    • 370 12.6. Расширение LINQ to Objects
      • 370 12.6.1. Проектирование и правила реализации
      • 372 12.6.2. Пример расширения: выбор произвольного элемента
    • 373 12.7. Резюме
  • 375 Часть IV. C# 4: приятно поиграть с другими
  • 377 Глава 13. Небольшие изменения для упрощения кода
    • 378 13.1. Необязательные параметры и именованные аргументы
      • 378 13.1.1. Необязательные параметры
      • 384 13.1.2. Именованные аргументы
      • 387 13.1.3 Объединение средств
    • 392 13.2. Усовершенствования для совместимости COM
      • 392 13.2.1. Ужасы автоматизации Word до C# 4
      • 393 13.2.2. Месть необязательных параметров и именованных аргументов
      • 394 13.2.3. Когда параметр ref не является ссылочным параметром
      • 394 13.2.4. Вызов именованных индексаторов
      • 396 13.2.5. Связывание основных сборок взаимодействия
    • 399 13.3. Обобщенная вариантность для интерфейсов и делегатов
      • 399 13.3.1. Типы вариантности: ковариация и контрвариация
      • 400 13.3.2. Использование вариантности в интерфейсах
      • 403 13.3.3. Использование вариантности в делегатах
      • 404 13.3.4. Сложные ситуации
      • 405 13.3.5. Ограничения и замечания
    • 409 13.4. Очень маленькие изменения в блокировке и полеподобных событиях
      • 409 13.4.1. Надежная блокировка
      • 410 13.4.2. Изменения в полеподобных событиях
    • 410 13.5. Резюме
  • 413 Глава 14. Динамическое связывание в статическом языке
    • 414 14.1. Что? Когда? Почему? Как?
      • 415 14.1.1. Что такое динамическая типизация
      • 415 14.1.2. Когда полезна динамическая типизация и почему
      • 417 14.1.3. Как C# 4 поддерживает динамическую типизацию
    • 417 14.2. Пятиминутное руководство по динамике
    • 420 14.3. Примеры динамической типизации
      • 420 14.3.1. Модель COM вообще и Microsoft Office в частности
      • 422 14.3.2. Динамические языки, такие как IronPython
      • 426 14.3.3. Динамическая типизация в простом управляемом коде
    • 432 14.4. Заглянем за кулисы
      • 432 14.4.1. Знакомство с исполняющей средой динамического языка
      • 433 14.4.2. Базовые концепции DLR
      • 436 14.4.3. Как компилятор C# справляется с динамикой
      • 440 14.4.4. Компилятор C# становится еще умнее
      • 443 14.4.5. Ограничения на динамический код
    • 446 14.5. Реализация динамического поведения
      • 446 14.5.1. Использование класса ExpandoObject
      • 450 14.5.2. Использование класса DynamicObject
      • 456 14.5.3. Реализация интерфейса IDynamicMetaObjectProvider
    • 460 14.6. Резюме
  • 463 Глава 15. Позволим нашему коду выражаться яснее с помощью Code Contracts
    • 464 15.1. Жизнь до Code Contracts
    • 466 15.2. Знакомство с Code Contracts
      • 468 15.2.1. Предусловия
      • 468 15.2.2. Постусловия
      • 470 15.2.3. Инварианты
      • 471 15.2.4. Утверждения и предположения
      • 473 15.2.5. Устаревшие контракты
    • 474 15.3. Перезапись бинарного кода при помощи ccrewrite и ccrefgen
      • 475 15.3.1. Простая перезапись
      • 476 15.3.2. Наследование контракта
      • 479 15.3.3. Сборки ссылок на контракт
      • 480 15.3.4. Поведение при нарушении
    • 482 15.4. Статическая проверка
      • 483 15.4.1. Знакомство со статической проверкой
      • 485 15.4.2. Неявные обязательства
      • 488 15.4.3. Выборочная проверка
    • 490 15.5. Документирование контрактов при помощи ccdocgen
    • 492 15.6. Практические контракты
      • 493 15.6.1. Философия: что в контракте?
      • 494 15.6.2. С чего начинать
      • 495 15.6.3. Возможности, всюду возможности
    • 498 15.7. Резюме
  • 501 Глава 16. Что дальше
    • 501 16.1. C# — комбинация традиций и новшеств
    • 502 16.2. Информатика и .NET
    • 503 16.3. Мир компьютеров
    • 504 16.4. Счастливого пути!
  • 505 Приложение А. Стандартные операторы запроса LINQ
    • 505 А.1. Объединение
    • 506 A.2. Конкатенация
    • 506 A.3. Преобразование
    • 508 A.4. Операторы элементов
    • 509 A.5. Равенство
    • 510 A.6. Генерация
    • 511 A.7. Группировка
    • 511 A.8. Объединения
    • 512 A.9. Разделение
    • 513 A.10. Проекция
    • 514 A.11. Кванторы
    • 514 A.12. Фильтрация
    • 515 A.13. Операторы на базе набора
    • 516 A.14. Сортировка
  • 517 Приложение Б. Обобщенные коллекции в .NET
    • 517 Б.1. Интерфейсы
    • 519 Б.2. Списки
      • 519 Б.2.1. Тип List<T>
      • 520 Б.2.2. Массивы
      • 521 Б.2.3. Тип LinkedList<T>
      • 522 Б.2.4. Типы Collection<T>, BindingList<T>, ObservableCollection<T> и KeyedCollection<TKey,TItem>
      • 523 Б.2.5. Типы ReadOnlyCollection<T> и ReadOnlyObservableCollection<T>
    • 523 Б.3. Словари
      • 523 Б.3.1. Тип Dictionary<TKey,TValue>
      • 524 Б.3.2. Типы SortedList<TKey,TValue> и SortedDictionary<TKey,TValue>
    • 525 Б.4. Наборы
      • 525 Б.4.1. Тип HashSet<T>
      • 525 Б.4.2. Тип SortedSet<T> (.NET 4)
    • 526 Б.5. Типы Queue<T> и Stack<T>
      • 526 Б.5.1. Тип Queue<T>
      • 527 Б.5.2. Тип Stack<T>
    • 527 Б.6. Параллельные коллекции (.NET 4)
      • 527 Б.6.1. Типы IProducerConsumerCollection<T> и BlockingCollection<T>
      • 528 Б.6.2. Типы ConcurrentBag<T>, ConcurrentQueue<T>, ConcurrentStack<T>
      • 528 Б.6.3. Тип ConcurrentDictionary<TKey,TValue>
    • 528 Б.7. Резюме
  • 531 Приложение В. Итог по версиям
    • 531 В.1. Главные выпуски инфраструктуры рабочего стола
    • 532 В.2. Средства языка C#
      • 532 В.2.1. C# 2.0
      • 532 В.2.2. C# 3.0
      • 533 В.2.3. C# 4.0
    • 533 В.3. Средства библиотеки
      • 533 В.3.1. .NET 2.0
      • 533 В.3.2. .NET 3.0
      • 534 В.3.3. .NET 3.5
      • 534 В.3.4. .NET 4
    • 535 В.4. Средства исполняющей среды (CLR)
      • 535 В.4.1. CLR 2.0
      • 536 В.4.2. CLR 4.0
    • 536 В.5. Сопутствующие инфраструктуры
      • 536 В.5.1. Compact Framework
      • 536 В.5.2. Silverlight
      • 537 В.5.3. Micro Framework
    • 537 В.6. Резюме
  • 539 Предметный указатель

Инструкция как скачать книгу Джон Скит: C#. Программирование для профессионалов в форматах DjVu, PDF, DOC или fb2 совершенно бесплатно.
C#. Программирование для профессионалов
Рейтинг книги:
0 голосов
1049

Поиск книг:




При поиске учитываются только слова, длина которых больше 3-х символов.

Статистика: