Бөлісу құралы:


Класс System.Reflection.Emit.AssemblyBuilder

Замечание

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

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

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

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

Чтобы получить объект AssemblyBuilder runnable, используйте метод 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

В .NET тип, производный PersistedAssemblyBuilder от AssemblyBuilder, позволяет сохранять динамические сборки. Дополнительные сведения см. в сценариях использования и примерах в 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 объектов. Вы можете загрузить определенную динамическую сборку и вызвать методы в загруженной сборке. Например, чтобы убедиться, что модули ресурсов включены в возвращаемый список модулей GetModules, вызовите Assembly на загруженном объекте GetModules. Если динамическая сборка содержит несколько динамических модулей, имя файла манифеста сборки должно совпадать с именем модуля, указанным в качестве первого аргумента DefineDynamicModule метода.

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

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

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

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