CompuMasterGmbH / CompuMaster.JitCompilation

CompuMaster.JitCompilation
MIT License
0 stars 0 forks source link

.NET 9 (re-)adds support for .NET Core for writing assemblies to disk #6

Open jochenwezel opened 5 months ago

jochenwezel commented 5 months ago

Quelle: https://entwickler.de/dotnet/dotnet-9-preview-1-preview-2?utm_source=Entwickler.de&utm_campaign=660356ecd8-ede_1824_tue_20240430_bastakoh_dotnet9&utm_medium=email&utm_term=0_-0fbb9489b0-%5BLIST_EMAIL_ID%5D&_branch_match_id=1203210589329713127&_branch_referrer=H4sIAAAAAAAAA02Luw6CMBRAvwY3oEIhxaQxGhia4IT7TR8XQSgQuMTfNzK5nkdHtGyXONbLEuFEn94OI66Rw7h5t9Ncipwrc93Jwzbvq0VZ%2FUenn7DaL7p%2FTTLPWZrlaJ0I0SGcRcKBdoSEJZzxlIHRG%2Blh7sDNNCEVx%2B7R9buX6HU%2FHoBw9ZJByFpjCi4Kw8Igu9eqeUL1uKkaVBlk5RfEQHZjuQAAAA%3D%3D

Mit .NET 9.0 ist es nun auch wieder möglich, zur Laufzeit erzeugte Assemblies im Dateisystem zu persistieren, indem die Methode Save() in der Klasse AssemblyBuilder verwendet wird (Listing 4). Diese Funktion war bereits im klassischen .NET Framework verfügbar (siehe Dokumentation zu Save() unter [3]). Im modernen .NET konnten zur Laufzeit erzeugte Assemblies bisher nur im RAM gehalten werden.

Listing 4: Speichern einer dynamisch erzeugten Assembly im Dateisystem

public void CreateAndSaveAssembly() { CUI.H2(nameof(CreateAndSaveAssembly));

string assemblyPath = Path.Combine(System.AppContext.BaseDirectory, "Math.dll");

AssemblyBuilder ab = AssemblyBuilder.DefinePersistedAssembly(new AssemblyName("Math"), typeof(object).Assembly); TypeBuilder tb = ab.DefineDynamicModule("MathModule").DefineType("MathUtil... ...

jochenwezel commented 2 months ago

Sample code from https://learn.microsoft.com/de-de/dotnet/core/whats-new/dotnet-9/overview

public void CreateAndSaveAssembly(string assemblyPath)
{
    AssemblyBuilder ab = AssemblyBuilder.DefinePersistedAssembly(
        new AssemblyName("MyAssembly"),
        typeof(object).Assembly
        );
    TypeBuilder tb = ab.DefineDynamicModule("MyModule")
        .DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);

    MethodBuilder mb = tb.DefineMethod(
        "SumMethod",
        MethodAttributes.Public | MethodAttributes.Static,
        typeof(int), [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);

    tb.CreateType();
    ab.Save(assemblyPath); // or could save to a Stream
}

public void UseAssembly(string assemblyPath)
{
    Assembly assembly = Assembly.LoadFrom(assemblyPath);
    Type type = assembly.GetType("MyType");
    MethodInfo method = type.GetMethod("SumMethod");
    Console.WriteLine(method.Invoke(null, [5, 10]));
}
jochenwezel commented 1 month ago

Basisklassenbibliothek: PersistedAssemblyBuilder anstelle von AssemblyBuilder

In .NET 9.0 Preview 1 (siehe Bericht im Windows Developer 6.2024) hatte Microsoft die aus dem klassischen .NET Framework bekannte Möglichkeit wieder eingeführt, dynamisch zur Laufzeit erstellte Assemblies im Dateisystem oder einem beliebigen Stream zu persistieren. In Preview 3 hat Microsoft das API aber nun geändert: Anstelle der zuvor verwendeten Klasse AssemblyBuilder

AssemblyBuilder ab = AssemblyBuilder.DefinePersistedAssembly(new AssemblyName("Math"), typeof(object).Assembly);
nutzt man nun die neue Klasse PersistedAssemblyBuilder:

PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("Math"), typeof(object).Assembly);
Listing 6 zeigt dazu ein Beispiel. Weitere Beispiele zur Anpassung der Metadaten, wie z. B. dem Einstiegspunkt, findet man in den Release Notes [16].

Listing 6: Beispiel zum Einsatz von PersistedAssemblyBuilder

string assemblyPath = Path.Combine(System.AppContext.BaseDirectory, "Math.dll");

PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("Math"), typeof(object).Assembly);
TypeBuilder tb = ab.DefineDynamicModule("MathModule").DefineType("MathUtil", TypeAttributes.Public | TypeAttributes.Class);

MethodBuilder mb = tb.DefineMethod("Sum", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [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);

tb.CreateType();
Console.WriteLine("Speichere Assembly unter: " + assemblyPath);
ab.Save(assemblyPath); // Speichern ins Dateisystem oder einen Stream

Quelle: https://entwickler.de/dotnet/net-9-preview-3-preview-4?utm_source=Entwickler.de&utm_campaign=15b6834bbc-ede_3224_tue_20240806_bastakoh_dotnet&utm_medium=email&utm_term=0_-0fbb9489b0-%5BLIST_EMAIL_ID%5D&_branch_match_id=1203210589329713127&_branch_referrer=H4sIAAAAAAAAA02LzQqCQBCAn8Zu6qarWLBEoZBkp7p0GnZ00kVXRWfp9SNPXb%2Bfjnlej2Go5zmgkT%2Bm7gdagobC5PrKGVtX3fDk2MI6uaUmVfxHu5%2BotZ21aUe1TzDNYolY%2B9QQxFEkgR1BJCIpMpEC6pV1P3XQTDwSb7elxjiryGozbIBpsUqAL96IB5kdUPhecqnKxxOK%2B7msoMy9JP8CC5aYCLgAAAA%3D