Можно ли написать сборку, которая динамически генерирует новый класс и исправляет себя новым классом?

Можно ли написать сборку, которая динамически генерирует/испускает новый класс и исправляет себя, чтобы включить новый класс?

Как?


person Triynko    schedule 20.05.2009    source источник
comment
Чего именно вы хотите добиться? Я думаю, может быть другой способ сделать то, что вы хотите сделать.   -  person Kirtan    schedule 20.05.2009
comment
Просто пытаюсь прояснить вопрос. В C# можно использовать System.CodeDom и System.CodeDom.Compiler для генерации и компиляции кода во время выполнения, загрузки полученной новой сборки и вызова ее посредством отражения. Ваш вопрос звучит так, будто это не то, чего вы хотите. Вы хотите исправить существующую сборку. Я правильно понимаю?   -  person Accipitridae    schedule 20.05.2009
comment
У меня есть сборка, развернутая на SQLServer, в которой есть классы данных, помеченные пользовательскими атрибутами. Для каждого помеченного класса я создаю статический метод, регистрируемый как скалярная функция CLR в SQLServer, который будет использоваться в проверочных ограничениях. Каждая функция пытается создать экземпляр одного класса и возвращает true в случае успеха. Это объединяет типы данных в моем приложении с базой данных. Чтобы не поддерживать этот список функций, я динамически генерирую класс и функции. Раньше этот класс писался вручную в той же сборке, но теперь он динамический. Я хочу одну dll.   -  person Triynko    schedule 20.05.2009
comment
Эти простые классы данных представляют ограниченные строки и числа. Построение завершается ошибкой, когда строка или число нарушает ограничение, которое является regex/min_length/max_length для строк или логическим лямбда-выражением (проверка диапазона или формула) для чисел. Таким образом, сгенерированные методы функционируют как ограничения значений, реализованные тестовой конструкцией экземпляра класса данных. Наличие двух отдельных сборок проблематично: например. ошибки зависимостей при обновлении или Произошла ошибка при сборе метаданных из сборки «имя сборки» с HRESULT 0x80131130. пытаюсь создать clr-функцию.   -  person Triynko    schedule 20.05.2009
comment
Когда я повторно развертываю исходную сборку (изменяю сборку) в SQLServer, это удается. Но когда я обновляю динамический аналог, который ссылается на него, изменение не выполняется, хотя я могу удалить/создать его заново. Ошибка ALTER ASSEMBLY не удалась, так как идентификатор "базы данных" сборки, на которую ссылаются, изменился. Убедитесь, что версия, имя и открытый ключ не изменились. ALTER ASSEMBLY завершилась неудачно, так как сборки, на которые ссылаются, изменились. Ссылочный список сборки должен оставаться прежним. Динамическая сборка выглядит нормально в Reflector, но я, должно быть, делаю что-то не так или это ошибка.   -  person Triynko    schedule 20.05.2009
comment
Другими словами... Раньше у меня был класс в сборке. Класс был удален и заменен функцией, которая вместо этого генерирует класс динамически. Я бы хотел, чтобы динамически сгенерированный класс был включен в сборку, которая его создает, поэтому я могу развернуть одну dll на SQL-сервере. ILMerge, кажется, работает, но я подумал, что может быть способ, который не включает создание промежуточной сборки с последующим вызовом утилиты командной строки.   -  person Triynko    schedule 20.05.2009


Ответы (2)


Я задал этот вопрос по-другому: Как с помощью AssemblyBuilder сделать все или любую сборку, на которую ссылаются, встроенной, а не связанной в сохраненной сборке?

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

Думается, так или иначе, для устранения зависимостей и упаковки содержимого нескольких сборок в одну утилита ILMerge является наиболее элегантным решением.

Единственная проблема заключается в том, что типы, сгенерированные в объединенной dll, несовместимы с теми же типами в обеих исходных dll. Если исходная DLL, например, создает новую сборку, объединяет ее с собой и загружает новую сборку... она не может использовать свои собственные типы для ссылки на вещи в новой сборке, которые соответствуют тому же типу в любой из оригинальные сборки.

Другими словами: класс A в [dll_generator] ссылается на [dll_1]. Класс A генерирует [dll_2], которая основана на [dll_1] и, конечно же, также ссылается на нее. Класс A вызывает ILMerge для объединения [dll_2] с его зависимостью [dll_1] для создания [dll_merged]. Ни один из типов в [dll_merged] не совместим ни с одним из их исходных типов в [dll_1] и [dll_2], поэтому, если класс A загружает [dll_merged] и пытается сделать с ним что-либо, включая литеральные имена типов из его исходной ссылки на [ dll_1], это не удается, потому что типы несовместимы. Единственный способ, которым класс A может работать с типами в [dll_merged], — загружать их по имени и полностью работать с объектами Type и отражением — или динамически компилировать исходный код с новым [dll_merged].

person Triynko    schedule 21.05.2009

Лучший способ сделать это — использовать внедрение зависимостей/инверсию управления или даже простой сервисный локатор.

Ваша новая сборка создаст новую конкретную реализацию и зарегистрирует ее вместо старой реализации.

Я уверен, что что-то более экзотическое было бы действительно ужасным взломом.

person Luke Schafer    schedule 20.05.2009
comment
Не могли бы вы объяснить это подробнее? По сути, у меня есть сборка для развертывания, и класс, который раньше кодировался в ней вручную, теперь генерируется динамически. Я хочу, чтобы этот класс был в исходной сборке, но я хотел, чтобы он динамически генерировался сборкой, а не кодировался мной вручную. Это возможно? - person Triynko; 20.05.2009
comment
что-то вроде autofac или windsor можно использовать для регистрации конкретных реализаций классов, которые затем вводятся из контейнера или извлекаются из него. Это простой способ организовать ваши реализации (и это ужасно простое объяснение). Если вы перепроектируете свое программное обеспечение таким образом, что исходная реализация извлекается из контейнера или локатора службы, вы можете легко переопределить это с помощью пользовательской реализации (если оригинал не запечатан). - person Luke Schafer; 21.05.2009
comment
Я не думаю, что это то, что я ищу. Классы данных уже существуют, и я просто расширял dll, чтобы иметь автоматически сгенерированные функции, которые создают экземпляры каждого класса данных и могут быть зарегистрированы как функции CLR в SQL Server. Это требует, чтобы динамически сгенерированный код был включен в исходную dll. Пока что решение, которое я использую, состоит в том, чтобы просто использовать ILMerge в качестве шага после отправки, и это прекрасно работает. - person Triynko; 21.05.2009