Является ли объект воплощением неизбежности реальности, когда необходимо разработать модульную архитектуру? - PullRequest
0 голосов
/ 04 февраля 2019

Общеизвестно, что приведение объектов является плохой практикой, и ее следует избегать, например, Почему следует избегать приведения? Вопрос получил несколько ответов с большими аргументами:

  1. Джерри Коффин:

    Глядя на вещи в более общем плане, ситуация довольно проста (по крайней мере, IMO): приведение (очевидно, достаточно) означает, что вы конвертируете что-то из одного типадругому.Когда / если вы делаете это, возникает вопрос "почему?"Если вы действительно хотите, чтобы что-то было определенного типа, почему вы не определили, что это тот тип, с которого нужно начинать?Это не значит, что нет никакой причины для такого преобразования, но всякий раз, когда это происходит, следует задать вопрос о том, можете ли вы изменить код так, чтобы везде использовался правильный тип.

  2. Эрик Липперт :

    Оба вида бросков - красные флаги.Первый тип приведений ставит вопрос: «Почему именно разработчик знает то, чего не знает компилятор?»Если вы находитесь в такой ситуации, то лучше всего изменить программу так, чтобы компилятор действительно справлялся с реальностью.Тогда вам не нужен актерский состав;анализ выполняется во время компиляции.Второй тип приведения ставит вопрос: «Почему операция не выполняется в целевом типе данных?»Если вам нужен результат в целых числах, тогда почему вы держите двойник на первом месте?Разве вы не должны держать int?

Переходя к моему вопросу, недавно я начал изучать исходный код известного проекта с открытым исходным кодом Автофиксирование , изначально разработанное Марком Симэнном, которое я очень ценю.

Одним из основных компонентов библиотеки является интерфейс ISpecimenBuilder, который как-то определяетабстрактный метод:

object Create(object request, ISpecimenContext context);

Как вы можете видеть, тип параметра запроса является объектом и, таким образом, он принимает совершенно разные типы, различные реализации интерфейса обрабатывают различные запросы по типу времени выполнения, проверяя, являются ли они чем-то кабельныминым образом возвращая какое-либо представление без ответа.

Кажется, что дизайн интерфейса не придерживается "хорошей практики", согласно которой приведение объектов должно использоваться редко.

Я былподумать про себя, если есть лучший способ составить этот контракт таким образом, чтобы победить все актеры, ноне мог найти никакого решения.Очевидно, что параметр объекта может быть заменен каким-то интерфейсом маркера, но это не избавит нас от проблемы приведения, я также подумал, что можно использовать некоторые варианты шаблона посетителя, как описано здесь , но это не кажетсячтобы быть очень масштабируемым, посетитель должен иметь десятки различных методов, поскольку существует очень много различных реализаций интерфейса, способных обрабатывать различные типы запросов.

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

Подводя итог, можно сказать, что приведение объектов и очень общие контракты являются неизбежностью реальности, когда необходимо разработать модульную и расширяемую архитектуру?

1 Ответ

0 голосов
/ 14 февраля 2019

Я не думаю, что могу ответить на этот вопрос вообще, для любого типа приложения или фреймворка, но я могу предложить ответ, который конкретно говорит об AutoFixture, а также предложить некоторые предположения о других сценариях использования.

Если бы мне сегодня пришлось писать AutoFixture с нуля, я бы поступил иначе.В частности, я бы не создавал повседневный API-интерфейс для чего-то вроде ISpecimenBuilder.Скорее, я бы разработал API для манипулирования данными вокруг концепции функторов и монад, как указано здесь .

. Этот дизайн полностью основан на обобщениях, но для него требуются статически типизированные строительные блоки(также описанный в статье), известный во время компиляции.

Это тесно связано с тем, как работает что-то вроде QuickCheck .Когда вы пишете тесты на основе QuickCheck, вы должны предоставить генераторы для всех ваших собственных пользовательских типов.Haskell не поддерживает приведение значений во время выполнения, но вместо этого полагается исключительно на универсальные шаблоны и некоторую автоматизацию во время компиляции.Конечно, дженерики Haskell являются более мощными, чем C #, поэтому вы не можете обязательно передавать знания, полученные из Haskell, в C #.Тем не менее, он предполагает, что можно писать код полностью, не полагаясь на приведение во время выполнения.

Однако AutoFixture поддерживает определяемые пользователем типы без необходимости написания пользовательских генераторов.Это делается через .NET Reflection.В .NET API Reflection нетипизирован;все методы для генерации объектов и вызова элементов принимают object в качестве ввода и возвращают object в качестве вывода.

Любое приложение, библиотека или инфраструктура, основанные на Reflection, должны будут выполнять некоторое приведение во время выполнения.Я не понимаю, как обойти это.

Можно ли написать генераторы данных без Reflection?Я не пробовал следующее, но, возможно, можно было бы принять стратегию, в которой можно было бы написать «код» для генератора данных непосредственно в IL и использовать Reflection emit для динамической компиляции сборки в памяти, которая содержитгенераторы.

Это немного похоже на работу контейнера Hiro , IIRC.Я полагаю, что можно было бы спроектировать другие типы универсальных сред на основе этой концепции, но я редко вижу, как это делается в .NET.

...