Системы. Рефлексия 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 этот метод. Динамические сборки можно создать с помощью одного из следующих режимов доступа:
-
Динамическая сборка, представленная приложением, 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.