У нас есть приложение, которое в целом используется как «общий» продукт несколькими разными клиентами, и в целом те же функции доступны для всех из них. Однако есть некоторые индивидуально разработанные компоненты, особенно относящиеся к импорту данных из соответствующих внутренних систем клиентов.Расширение классов базовых моделей для конкретных случаев использования
До сих пор это в основном означало преобразование различных входных форматов в одни и те же структуры данных, но все чаще становится важным сохранять дополнительные данные для конкретных клиентов для некоторых типов и использовать их снова в отдельных частях кода, которые также «знают» о это конкретный клиент. В целом это не будет много разных мест в приложении.
Чтобы сделать это без «загрязняющих» классов основных моделей, эта «расширяемость» в настоящее время достигается за счет того, что классы, о которых идет речь, получают от DynamicObject
, а затем имеют некоторый код для динамического определения свойств, связанных с магическими строками и в других местах проверьте их и извлеките их, что даже не безопасно для типов, так как вам нужно знать, для чего нужно сделать возможное значение.
Я довольно недоволен этим и хотел бы предложить решение, которое немного напоминает «переключение обезьян» и более идиоматично в статически типизированной среде. Вопрос в том, какой лучший вариант для этого. (Дополнительное требование состоит в том, что дополнительные данные должны быть легко сериализаций/десериализации с остальной частью объекта.)
- «очевидная» вещь в объектно-ориентированном языке, конечно, будет подклассы типов моделей, но это создает ряд новых проблем при создании и копировании объектов и, как правило, мне не нравится то, что мне очень нравится (и это просто нарушает «состав над наследованием»).
- Решение, которое по-прежнему использует наследование, но ограничивает его влияние, будет добавление единственного свойства
ExtensionData
к фактическому классу, его тип будет пустым классом*ExtensionData
, который затем подклассифицируется для каждого клиента. Использование этого метода предполагает некоторую проверку и литье типов для фактического объекта данных расширения, но помимо этого, он будет полностью безопасным по типу. Я думаю, что это мой любимый способ прямо сейчас. - То, что очень похоже на используемый динамический подход, будет заменять типизированный объект из предыдущего варианта
Dictionary<string, object>
. Я думаю, что это все еще лучше, чем сейчас, но у него есть одна и та же фундаментальная проблема: динамически набирать и использовать магические строки (хотя они, конечно, будут храниться как константы).
Данные расширения не должны быть фактически динамическими; как только известно, какие данные клиента импортируются, мы находимся в четко определенном субдомене без каких-либо сюрпризов относительно того, что находится в импортируемых данных.
(Как это часто бывает, это было бы проще в F #, где я мог бы использовать свойства расширенного расширения или иметь ExtensionData
как DU, где каждый случай имеет тип записи конкретного клиента, который будет однозначно идентифицирован с помощью сопоставления с образцом .)
Что является самым «идиоматическим» и поддерживаемым способом сделать это на C#? Есть ли у одной из упомянутых альтернатив огромные преимущества или недостатки, которые я не рассматривал?