Системы. Рефлексия ion. Класс Emit.AssemblyBuilder

В этой статье приводятся дополнительные замечания к справочной документации по этому API.

Динамическая сборка — это сборка, созданная с помощью API-интерфейсов Рефлексия ion Emit. Динамическая сборка может ссылаться на типы, определенные в другой динамической или статической сборке. Вы можете использовать AssemblyBuilder для создания динамических сборок в памяти и выполнения кода во время выполнения того же приложения. В .NET 9 мы добавили новый файл PersistedAssemblyBuilder с полностью управляемой реализацией отражения, которая позволяет сохранить сборку в файле. В платформа .NET Framework можно выполнить оба действия: запустить динамическую сборку и сохранить ее в файле. Динамическая сборка, созданная для сохранения, называется сохраняемой сборкой, а обычная сборка только для памяти называется временной или запущенной. В платформа .NET Framework динамическая сборка может состоять из одного или нескольких динамических модулей. В .NET Core и .NET 5+ динамическая сборка может состоять только из одного динамического модуля.

Способ создания экземпляра отличается для каждой AssemblyBuilder реализации, но дальнейшие шаги по определению модуля, типа, метода или перечисления, а также для записи IL довольно похожи.

Запускаемые динамические сборки в .NET

Чтобы получить объект runnable AssemblyBuilder , используйте AssemblyBuilder.DefineDynamicAssembly этот метод. Динамические сборки можно создать с помощью одного из следующих режимов доступа:

  • AssemblyBuilderAccess.Run

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

  • AssemblyBuilderAccess.RunAndCollect

    Динамическая сборка, представленная модулятором AssemblyBuilder , может использоваться для выполнения созданного кода и автоматически удаляется сборщиком мусора.

Режим доступа необходимо указать, указав соответствующее AssemblyBuilderAccess значение в вызове AssemblyBuilder.DefineDynamicAssembly метода при определении динамической сборки и не может быть изменено позже. Среда выполнения использует режим доступа динамической сборки для оптимизации внутреннего представления сборки.

В следующем примере показано, как создать и запустить сборку:

public void CreateAndRunAssembly(string assemblyPath)
{
    AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("MyAssembly"), AssemblyBuilderAccess.Run);
    ModuleBuilder mob = ab.DefineDynamicModule("MyModule");
    TypeBuilder tb = mob.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
    MethodBuilder mb = tb.DefineMethod("SumMethod", MethodAttributes.Public | MethodAttributes.Static,
                                                                   typeof(int), new Type[] {typeof(int), typeof(int)});
    ILGenerator il = mb.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Ret);

    Type type = tb.CreateType();

    MethodInfo method = type.GetMethod("SumMethod");
    Console.WriteLine(method.Invoke(null, new object[] { 5, 10 }));
}

Сохраняемые динамические сборки в .NET

Новый PersistedAssemblyBuilder тип, производный от и AssemblyBuilder позволяющий сохранять динамические сборки в .NET Core, проверка сценарии использования и примеры на странице PersistedAssemblyBuilder.

Сохраняемые динамические сборки в платформа .NET Framework

В платформа .NET Framework динамические сборки и модули можно сохранить в файлах. Для поддержки этой функции AssemblyBuilderAccess перечисление объявляет два дополнительных поля: Save и RunAndSave.

Динамические модули в сохраняемой динамической сборке сохраняются при сохранении динамической сборки с помощью Save метода. Чтобы создать исполняемый файл, SetEntryPoint необходимо вызвать метод, чтобы определить метод, который является точкой входа в сборку. Сборки сохраняются как библиотеки DLL по умолчанию, если SetEntryPoint метод не запрашивает создание консольного приложения или приложения под управлением Windows.

В следующем примере показано, как создать, сохранить и запустить сборку с помощью платформа .NET Framework.

public void CreateRunAndSaveAssembly(string assemblyPath)
{
    AssemblyBuilder ab = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("MyAssembly"), AssemblyBuilderAccess.RunAndSave);
    ModuleBuilder mob = ab.DefineDynamicModule("MyAssembly.dll");
    TypeBuilder tb = mob.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
    MethodBuilder meb = tb.DefineMethod("SumMethod", MethodAttributes.Public | MethodAttributes.Static,
                                                                   typeof(int), new Type[] {typeof(int), typeof(int)});
    ILGenerator il = meb.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Ret);

    Type type = tb.CreateType();

    MethodInfo method = type.GetMethod("SumMethod");
    Console.WriteLine(method.Invoke(null, new object[] { 5, 10 }));
    ab.Save("MyAssembly.dll");
}

Некоторые методы базового Assembly класса, такие как GetModules и GetLoadedModules, не будут работать правильно при вызове из AssemblyBuilder объектов. Вы можете загрузить определенную динамическую сборку и вызвать методы в загруженной сборке. Например, чтобы убедиться, что модули ресурсов включены в возвращаемый Assembly список модулей, вызовите GetModules загруженный объект. Если динамическая сборка содержит несколько динамических модулей, имя файла манифеста сборки должно совпадать с именем модуля, указанным в качестве первого аргумента DefineDynamicModule метода.

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

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

Ограничения на выдачу доменов удаленных приложений

Для некоторых сценариев требуется создать динамическую сборку и выполнить ее в домене удаленного приложения. Рефлексия инициации не позволяет динамической сборке создаваться непосредственно в домен удаленного приложения. Решение состоит в том, чтобы выпустить динамическую сборку в текущем домене приложения, сохранить динамическую сборку на диск, а затем загрузить динамическую сборку в домен удаленного приложения. Домены удаленного взаимодействия и приложений поддерживаются только в платформа .NET Framework.