Страницы

Поиск по вопросам

воскресенье, 29 декабря 2019 г.

Аналог partial class для разных assemblies

#c_sharp #aspnet #aspnet_mvc #архитектура


Мне необходимо реализовать несколько сайтов на ASP.NET MVC (C#).
Во всех сайтах есть общие компоненты (пользователи (регистрация, вход, личные сообщения,
восстановление пароля и т.д.), группы, админка, новости и т.д.). Соответственно, я
хочу сделать одну общую библиотеку для использования во всех проектах.
Проблема заключается в том, что нужно иметь возможность добавлять поля классам библиотеки,
при этом и библиотека должна знать о новых полях (для правильной загрузки из бд (используется
OrmLite) и кэширования (используется redis)).
К тому же хотелось бы избежать конверсий типов или указания generic аргументов в
коде сайта:
var user = (MyUser)User.Load(id);
var user = User.Load(id);

Например, базово класс User имеет поля id и name. На сайте 1 нужно добавить поле
email. А на сайте 2 нужно добавить поле phone (вместо email).
Если бы была одна библиотека (assembly), то это легко решалось бы с помощью partial
class.
Есть у кого идеи, как решить данную задачу?    


Ответы

Ответ 1



Вы смотрите на partial классы под неверным углом зрения. Думаю лучшее объяснение того в чем здесь неточность - это описание причин, по которым частичные классы были созданы. В первой версии C# частичных классов не было и это приводило к сложностям в работе с генерируемым кодом. Например, если вы сейчас используете Windows Forms, то код формы, который генерируется дизайнером, располагается в одном файле, а код, который пишете для формы вы - в другом. В C# 1 все лежало в одном файле и это вызывало серьезные проблемы. С одной стороны вы должны были вести себя осторожно, чтобы не сломать сгенерированный код, с другой стороны генератор кода должен был обходить стороной ваш код. И эти проблемы возможны не только в gui-фреймворках, генерирующих код для создания графического интерфейса. Генерация кода используется, например, в ORM. Наконец, вы сами можете захотеть написать свой генератор. Появление частичных классов в C# 2 решило эту проблему. Именно для этого были созданы частичные классы - чтобы была возможность описать один класс в нескольких файлах. Это позволило изолировать генерируемый код в отдельных файлах. С тех пор были придуманы другие способы использования частичных классов, но и в этих способах причина применения частичных классов та же - необходимость разделить один класс на несколько файлов. Например: при написании unit-тестов обычно на каждый тестируемый класс создается один класс с тестами. Класс с тестами часто становится очень большим, намного большим чем тестируемый класс. В таких случаях класс с тестами можно сделать частичным и разделить на несколько файлов при рефакторинге кода часто встречается задача декомпозиции большого класса. Частичные классы в этом случае могут упростить работу. Можно сначала сделать класс частичным и безопасно разделить его на несколько файлов. И только когда все швы окончательно проясняться, выполнить реальное разделение на несколько классов. Эти способы применения частичных классов отличаются от основного, но в них частичные классы служат той же цели: они позволяют описать один класс в нескольких файлах. То что собираетесь сделать вы - совсем другое дело. Вы собираетесь описать несколько классов с помощью синтаксиса частичных классов. То есть вы хотите описать несколько классов так, как будто это один класс. Более того, вы пытаетесь найти способ описать этот класс так, чтобы он лежал в нескольких сборках. Это равносильно кирпичу, который делят между собой стены соседних зданий. Поэтому ответ на ваш вопрос такой - аналога partial class для разных assemblies не существует, вряд ли когда то будет существовать и не стоит пытаться его сымитировать.

Ответ 2



partial-классы между сборками существовать не могут. Зато можно сделать так, чтобы два проекта собирались в итоге в одну и ту же сборку. Делается это так. Открываем проект с библиотекой, и дописываем ближе к концу что-то наподобие вот этого: Теперь открываем файл с основным проектом, и дописываем вот такое: Все, теперь при компиляции все файлы с исходным кодом из библиотеки окажутся как бы включенными в ваш основной проект. Разумеется, это еще не все - ведь проект состоит не только из файлов с исходным кодом. Как минимум, придется таким же образом импортировать зависимости из библиотеки (References) - а также переписать логику загрузки пакетов из репозитория NuGet. Если в библиотеке есть ресурсы (EmbeddedResource) - понадобится импортировать еще и их. Но это все - решаемые проблемы. Также может возникнуть проблема с R# - он не понимает динамического добавления файлов в проект. Для него понадобится включить проект с библиотекой как обычную зависимость - а потом не забыть убрать средствами MSBuild перед компиляцией: Так что в целом то, что вы хотите, вполне достижимо. Но подумайте - не будет ли наследование с обобщенными типами проще?

Комментариев нет:

Отправить комментарий