Skip to content

Exporting an assembly

To keep editable source, drafts, dependencies, and previous results, save a session. Assembly export creates a .dll for use outside ilrepl.

.save writes the current cell as a real assembly with a static IlRepl.Cell.Run method, every method defined with .method beside it, and every type defined with .class before it. The cell is kept, so you can still run it.

Saved edits include their types and helpers. Use the names shown by .types when loading the file. The export contains the latest saved revisions; the session keeps their originals.

il[1]> .args (int32 n = 0)
args: 0:int32 n = 0
il[1]> ldarg n
┊ [int32]
il[1]> ldc.i4 2
┊ [int32, int32] ◂ top
il[1]> mul
┊ [int32]
il[1]> .save doubler.dll
wrote /path/to/doubler.dll with IlRepl.Cell.Run

The path in the output is absolute; /path/to above stands for your current directory. Save this as inspect.cs beside doubler.dll and run dotnet run --file inspect.cs. The file-based app uses the JIT so it can load the generated assembly:

#:property PublishAot=false
using System.Reflection;
var assembly = Assembly.LoadFrom("doubler.dll");
var run = assembly.GetType("IlRepl.Cell")!.GetMethod("Run")!;
Console.WriteLine(run.Invoke(null, [21])); // 42

Session methods are public static methods on the same type, so GetMethod("Fib") finds them the same way, and a session type is a type of the assembly under its own name, Point or Outer+Inner. The file is written by the same Mono.Cecil writer that produces the types the session runs, so it carries what you declared and nothing else: the layouts and offsets, the constants and modifiers, parameter defaults, attributes, and no constructor you did not write. A call from one session method to another is a direct call in the file, and nothing in it refers back to the session.

Exporting does not run the cell, constructors, or method edits. The destination is replaced only after the complete assembly has been written. Cancellation or a write failure leaves an existing destination unchanged.

.il renders the types, the methods, and the cell as ILAsm source, and .save with an .il extension is not needed because you can copy it from the transcript. Operands are fully qualified and each class is written out with its fields, members, and nested types, so the text assembles with ilasm after adding the assembly references it lists.

For method edits, .il includes the copied types and assembly references needed by Microsoft ILAsm. It also shows unfinished cells. Complete any pending labels and exception blocks before saving or assembling them.

il[1]> .il
.assembly extern System.Runtime {}
.assembly ilrepl_cell {}
.module ilrepl_cell.dll
.class public abstract sealed auto ansi beforefieldinit IlRepl.Cell extends [System.Runtime]System.Object
{
.method public static object Run(int32 n) cil managed
{
.maxstack 2
.zeroinit
ldarg n
ldc.i4 2
mul
box int32
ret
}
}

In a script or --eval, ending with .save or .session save saves the source without running the pending cell.