Статическая (время компиляции / строго типизированная) поддержка множественной диспетчеризации в C#
Недавно я снова и снова использовал один и тот же шаблон в своем коде. По сути, это вариант шаблона посетителя, который я использую для преобразования ссылок на экземпляры базовых классов в производные. Этот подход требует много стандартного кода.
Вопросы:
- Как я могу мульти-рассылать метод в C# статически / строго типизированным способом без написания тонны кода посетителей?
- Есть ли инструмент / расширение, которое генерирует этот код?
- Почему в языке C# нет ничего, что решало бы вопросы множественной диспетчеризации? Я не верю, что я единственный, кто находит это раздражающим. Я могу быть ужасно неправ, и проблема не существует, поэтому я хотел бы знать, как вы справляетесь с этим.
1 ответ
Как мульти-диспетчеризировать метод в C# статическим / строго типизированным способом без написания тонны кода посетителей?
Я не знаю какой-либо техники для этого.
В версии Roslyn компилятора C#, написанной на C#, мы используем шаблон посетителя повсеместно в иерархиях типов, которые имеют десятки или сотни членов. Мы написали утилиту, которая преобразует XML-описание типов в объявления типов вместе с базовыми классами для посетителей. Это, кажется, работает очень хорошо для нас.
Есть ли инструмент / расширение, которое генерирует этот код?
Есть; мы написали это сами. Это было не сложно. Вы можете сделать то же самое.
Почему в C# как языке нет ничего, что могло бы решить проблему множественной диспетчеризации?
У нас есть список возможных языковых особенностей буквально длиннее вашей руки. В каждом конкретном выпуске у нас есть бюджет, чтобы сделать два или три из них, вершины, и поэтому мы концентрируемся на получении максимально возможной отдачи от затраченных средств.
Упрощение реализации двойной (или множественной) виртуальной отправки с помощью автоматической генерации шаблона посетителя никогда не делало его где-либо ближе к вершине этого списка. Существуют буквально десятки других возможных шаблонов, которые мы могли бы внедрить в язык, которые являются "ударом по карману". Проведя обзор популярных языков, вы обнаружите, что очень немногие языки поддерживают двойную или множественную виртуальную диспетчеризацию с помощью статического анализа, а те, которые не пользуются большой популярностью. Для этого есть причина: во-первых, потому что это на самом деле не очень полезная функция, и, во-вторых, потому что, когда вам это нужно, вы можете достичь ее, внедрив шаблон самостоятельно или с помощью динамической диспетчеризации.
Как вы заметили, существуют существенные недостатки как подхода, основанного на шаблонах, так и подхода динамического распределения. Но, хотя есть и недостатки, они оба могут быть реализованы обычными разработчиками в случае необходимости. При оценке того, какие шаблоны встраивать в язык, мы склоняемся к тем шаблонам, которые обычным разработчикам действительно довольно сложно реализовать, используя подход, основанный на шаблонах. Шаблон посетителя не сложен; это просто многословно.
Например: в C# 2 мы решили встроить шаблон "генератора последовательности" в язык. В C# 3 мы решили встроить в язык паттерн "понимание запросов с помощью монад последовательности". В C# 4 мы решили встроить шаблон "динамической отправки" в язык. В C# 5 мы решили встроить шаблон "передать текущее продолжение как делегат" в язык. Все это примеры большого "взрыва за доллар" - они были дорогостоящими возможностями для реализации, но они принципиально делают новые стили программирования доступными на базовом языке.
В любом выпуске доступно лишь ограниченное количество усилий; встраивание одного шаблона в язык в выпуске не позволяет нам встраивать любые другие шаблоны в язык в этом выпуске, потому что на это просто нет бюджета.
Когда встраивание шаблона "двойной (или множественной) виртуальной отправки" в язык становится наилучшим способом потратить наш бюджет, мы сделаем это, и не раньше. Поэтому вам следует ожидать долгого ожидания.