Делаем внутренние сборки видимыми для другой сборки во время выполнения

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

В общем, у меня есть игровая приставка. Консоль запускает фрагменты кода C#. Скомпилированная сборка должна быть другом текущей сборки, чтобы консоль знала обо всех типах в текущей сборке и могла ими манипулировать.

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

Проблема вторая: если я заставлю каждую сборку использовать отдельный AppDomain, а затем выгружу последний, это сработает, но я не смогу манипулировать объектами из текущего AppDomain, потому что они не являются производными от MarshalByRef, поэтому, когда я передаю их в качестве параметров в script он пытается сериализовать их. Мне не нравятся домены приложений.

Поэтому я решил, что самым безболезненным способом будет просто создать сборки в одном и том же AppDomain с разными именами и каким-то образом установить их как дружественные сборки во время выполнения.

Я понимаю, что это может быть невозможно, поэтому приветствуются любые другие альтернативы.

РЕДАКТИРОВАТЬ: Чтобы сделать это более ясным. Сценарий должен получить доступ к внутренним компонентам основной/родительской сборки. А не наоборот. Я не могу сделать все общедоступным в основной сборке, потому что я хочу, чтобы код можно было использовать повторно.


person Luka Horvat    schedule 06.06.2012    source источник
comment
Создана ли эта сборка для размещения фрагментов кода? Почему бы просто не сделать типы общедоступными?   -  person Adam Houldsworth    schedule 06.06.2012
comment
msdn.microsoft. com/ru-ru/library/   -  person angularrocks.com    schedule 18.02.2014


Ответы (4)


Если вы создаете эти сборки, почему бы просто не сделать нужные вам элементы общедоступными public вместо internal?

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

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

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

Можно ли динамически добавлять атрибуты в C#?

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

person Adam Houldsworth    schedule 06.06.2012
comment
Я хочу, чтобы внутренние компоненты основных сборок были видны сценарию, а не наоборот. И я нахожусь в ситуации, когда я не могу сделать классы общедоступными, потому что я хочу повторно использовать эту консоль, и я не могу сделать все общедоступным только для того, чтобы это работало. - person Luka Horvat; 06.06.2012
comment
@Darwin В таком случае я не думаю, что ты сможешь это сделать. В конце концов, ваша основная сборка — это просто API для сгенерированных, нет ничего плохого в публичном раскрытии типов для использования. - person Adam Houldsworth; 06.06.2012
comment
Отражение может быть здесь очень жизнеспособным, но я не уверен, что оно сработает. Если я пропущу дружбу со сборками и просто передам вещи как объект, а затем динамически приведу их к соответствующим типам, которые я получаю с помощью отражения... Не столкнусь ли я с проблемами, если тип, который я получил, содержит другой тип, который не должен быть видимым по умолчанию ? - person Luka Horvat; 06.06.2012
comment
@Darwin Reflection имеет множество потенциальных проблем. В качестве альтернативы, если вам нужно предоставить функциональные возможности в другой сборке, в основной сборке пометьте их как protected internal, а затем выполните производные от них в сгенерированной сборке. Затем типы в сгенерированной сборке могут использовать этот производный тип. - person Adam Houldsworth; 06.06.2012
comment
Это оказывается намного сложнее, чем я должен был бы... Есть ли способ как-то изменить существующую сборку вместо создания новой при каждой компиляции? Это было бы идеально, так как я мог бы добавить их в друзья и избежать утечки памяти. - person Luka Horvat; 06.06.2012
comment
@Darwin Изменить модификатор доступа для типов несложно, и, похоже, вы уже проделали некоторую работу, чтобы компилировать код. Это просто случай правильного раскрытия того, что вы хотите показать. Я не вижу причин в том, чтобы типы не были общедоступными, если вы используете их публично. - person Adam Houldsworth; 06.06.2012
comment
Но я действительно не хочу, чтобы каждый класс был общедоступным только для того, чтобы я мог использовать его из одной другой сборки. Должен быть способ запускать код несколько раз, чтобы по-прежнему иметь доступ к закрытым классам. - person Luka Horvat; 06.06.2012
comment
@Darwin Вам не обязательно это делать, это будет самое простое решение. protected internal — допустимый вариант, но это скорее обходной путь, чем реальное решение проблемы. Я знаю, что можно изменить/добавить атрибуты к экземплярам типов во время выполнения, но я пока не нашел кода для этого в текущей сборке. - person Adam Houldsworth; 06.06.2012

Вы можете добавить InternalsVisibleToAttribute в новую сборку.

person Denis Palnitsky    schedule 06.06.2012
comment
Разве это не сделает внутренние скрипты видимыми для основной сборки, а не наоборот? - person Luka Horvat; 06.06.2012
comment
@Bond Думаю, да, если собрать сборку с нуля - person Denis Palnitsky; 06.06.2012
comment
@Darwin сделает все внутренние типы сборки с атрибутом видимыми для указанной сборки, но не наоборот. - person Denis Palnitsky; 06.06.2012
comment
Проблема в том, что я хочу наоборот. - person Luka Horvat; 06.06.2012
comment
Так что, возможно, стоит рассмотреть какие-то другие способы связи. Протокол XML, например. Без уточнения сложно угадать. - person Denis Palnitsky; 06.06.2012

Это не кажется возможным. Вы можете просто сгенерировать элементы каждой сборки как public — поскольку сборка создается динамически, это не должно быть проблемой.

person Ventsyslav Raikov    schedule 06.06.2012

Я думаю о проблеме, похожей на вашу, и рассматриваю какую-то прокси-сборку, которая предоставляет общедоступные методы внутренним компонентам основной сборки.

Сборки:

  • Основной: с внутренними компонентами и внутренностями, видимыми для прокси-сборки;
  • Прокси: с общедоступными методами для косвенного доступа к внутренней части основного;
  • Потребитель: может получить доступ к прокси для изменения файла main.

В моем случае моя основная сборка является повторно используемым компонентом, и у меня есть два типа потребителей. Первый вид просто использует повторно используемые компоненты внутри моей основной сборки и, таким образом, имеет доступ только к общедоступным членам основной сборки. Второй потребитель – тестовая сборка, тестирующая первую упомянутую потребительскую сборку. Эта сборка обычно хочет имитировать некоторые внутренние элементы основной сборки и поэтому использует прокси-сервер для доступа к этим внутренним элементам.

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

person Sander    schedule 21.03.2013