2023-01-29

How to copy a method from an existing assembly to a dynamic assembly in .NET Core?

I want to somehow add a method from an on disk assembly to an assembly I am generating, I am creating the assembly via the System.Reflection.Emit and saving it to a file using the Lokad.ILPack nuget package and loading it with AssemblyLoadContext since this is .NET 7 Core, the on disk assembly is also generated.

I would like to avoid using externals libraries, but I understand that it may not be plausible using the standard library, and I can't use something like Pinvoke because the assembly might not even exist when the method call is needed, also if the answer requires copying the type containing the method then that's fine.

Example of how I am creating the assembly:

public static void CreateMethod(string destDllPath)
{
    AssemblyName asmName = new AssemblyName("CAssembly");

    AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndCollect);
    //Its RunAndCollect because if the AssemblyLoadContext fails to unload it will do so automatically

    ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("CModule");

    TypeBuilder typeBuilder = modBuilder.DefineType("CType", TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed);
    //Abstract | Sealed means that the class is static

    MethodBuilder methodBuilder = typeBuilder.DefineMethod("CMethod",
        MethodAttributes.Static | MethodAttributes.Public,
        CallingConventions.Standard,
        typeof(bool),
        new[] { typeof(bool) });


    ILGenerator ILG = methodBuilder.GetILGenerator();

    ILG.Emit(OpCodes.Ldarg_0);
    //Push the first argument onto the evaluation stack
    ILG.Emit(OpCodes.Ret);
    //Return the first element from the evaluation stack

    _ = typeBuilder.CreateType();

    AssemblyGenerator asmGenerator = new AssemblyGenerator();
    asmGenerator.GenerateAssembly(asmBuilder, destDllPath);
}

Then using the method generated above

public static void CopyMethod(AssemblyBuilder toAssembly, string fromDllPath)
{
    string typeName = "CType";
    string methodName = "CMethod";

    Assembly fromAssembly = Assembly.LoadFile(fromDllPath);
    //note that the assembly at fromDllPath is created via MethodBuilder ILGenerator and Lokad.ILPack

    Type type = fromAssembly.GetType(typeName)!;

    MethodInfo method = type.GetMethod(methodName)!;

    //to test that the generated assembly is valid
    //bool testTesult = (bool)method.Invoke(null, new object[] { true });

    //somehow add method to toAssembly?
}

This is where I run into the problem of not knowing how to add the method to the assembly

I have spend a solid few days trying the find a solution to this problem, but there doesn't seem to be al ot of information on dynamic assembly creation in .NET Core 5 through 7.



No comments:

Post a Comment