Awesome
InlineIL.Fody <picture><source media="(prefers-color-scheme: dark)" srcset="icon-dark.png"><img src="icon.png" align="right" alt="Logo"></picture>
This is an add-in for Fody which lets you inject arbitrary IL into your assembly at compile time. <br clear="right" />
<table> <tr> <th width="415px">The following C# code</th> <th width="415px">Is compiled to the following IL</th> </tr> <tr> <td>using static InlineIL.IL.Emit;
public static class Example
{
public static void ZeroInit<T>(ref T value)
where T : struct
{
Ldarg(nameof(value));
Ldc_I4_0();
Sizeof(typeof(T));
Unaligned(1);
Initblk();
}
}
</td>
<td>
.method public hidebysig static void ZeroInit
<valuetype .ctor
([System.Runtime]System.ValueType) T> (
!!T& 'value'
) cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: sizeof !!T
IL_0008: unaligned. 1
IL_000b: initblk
IL_000d: ret
}
</td>
</tr>
</table>
Installation
-
Include the
Fody
andInlineIL.Fody
NuGet packages with aPrivateAssets="all"
attribute on their<PackageReference />
items. InstallingFody
explicitly is needed to enable weaving.<ItemGroup> <PackageReference Include="Fody" Version="..." PrivateAssets="all" /> <PackageReference Include="InlineIL.Fody" Version="..." PrivateAssets="all" /> </ItemGroup>
-
If you have a
FodyWeavers.xml
file in the root directory of your project, add the<InlineIL />
tag there. Otherwise, the following file will be created on the first build if it doesn't exist:<?xml version="1.0" encoding="utf-8" ?> <Weavers> <InlineIL /> </Weavers>
See Fody usage for general guidelines, and Fody configuration for additional options.
Usage
Call static methods of the InlineIL.IL.Emit
class to emit IL instructions. That's it. :wink:
A few more things which are good to know:
-
The
InlineIL.IL
class exposes methods for handling labels and local variables, and some utilities (see below). -
System.Type
is implicitly convertible toInlineIL.TypeRef
: when you see aTypeRef
parameter, you can use thetypeof
keyword in most cases. -
You can use the
IL.Push
method to push anything onto the evaluation stack. In particular, this lets you access C# variables, as you cannot emit anldloc
instruction for those. -
You can add the
using static InlineIL.IL.Emit;
directive to get rid of theIL.Emit
prefix. -
You don't have to emit instructions in their short form, they will be shortened automatically (e.g.
ldarg.0
will be emitted instead ofldarg 0
). -
Most types used as operands declare instance methods which change their meaning and can be chained, for instance:
new TypeRef(...).MakeArrayType().MakeByRefType()
. -
You can combine InlineIL instructions with existing C# code: a given method doesn't have to be entirely written in IL. After weaving, the reference to the
InlineIL
assembly is removed from your project.
Methods
-
IL.Emit.*
Every method call on theIL.Emit
class will be replaced by the IL instruction it represents.
Note that all arguments to these methods need to be constructed in place (i.e. the instruction needs to be representable in IL). -
IL.DeclareLocals
Declares local variables. Supports changing theinit
flag and pinned variables. Local variables can be referenced by name or by index. -
IL.MarkLabel
Marks a label at a given position in the code. -
IL.Push
,IL.PushInRef
,IL.PushOutRef
Pushes the provided argument onto the evaluation stack. Does not require a constant argument, any expression should work. If an error is raised in optimized builds, try to useIL.EnsureLocal
to change the layout of the IL emitted by the compiler, so it becomes compatible. -
IL.Pop
Pops a value from the evaluation stack into a local variable or static field. -
IL.Unreachable
Marks an unreachable code region, for instance just after aret
instruction. Necessary when the compiler's control flow analysis requires a code statement.
Usage:throw IL.Unreachable();
-
IL.Return
,IL.ReturnRef
,IL.ReturnPointer
Helper methods to return the value from the top of the evaluation stack.
Example usage:return IL.Return<int>();
-
IL.EnsureLocal
Helper method that forces the compiler to emit an IL local for the supplied local variable, instead of keeping its value on the evaluation stack only. This can let a local variable be used withIL.Push
in optimized builds, where the IL layout wouldn't allow it otherwise.
Types
-
TypeRef
A class which represents a type. Note thatSystem.Type
is implicitly convertible toTypeRef
, so you can directly writetypeof(int)
for instance where aTypeRef
parameter is expected. -
MethodRef
A method reference. Exposes a simple constructor for methods without overloads, and some more detailed ones for overload disambiguation. Additional static factory methods for referencing underlying methods of properties and events are provided for convenience.
UseTypeRef.TypeGenericParameters[N]
andTypeRef.MethodGenericParameters[N]
to represent the generic parameter of indexN
inMethodRef
calls which involve overload resolution. -
FieldRef
A field reference. -
StandAloneMethodSig
A method signature for use as an operand to thecalli
instruction. -
LocalVar
Declares a local variable (with an optional name), for use withIL.DeclareLocals
. Implicitly convertible fromSystem.Type
if you don't want to use named locals or pinning.
Configuration
The <InlineIL />
element in FodyWeavers.xml
accepts the following attributes:
-
SequencePoints="True|False|Debug|Release"
, default value:Debug
Defines if sequence points should be generated for each emitted IL instruction. The defaultDebug
value improves the debugging experience in Debug builds without impacting the JIT codegen in Release builds. -
Warnings="Warnings|Ignore|Errors"
, default value:Warnings
Defines how warnings should be handled.Ignore
hides them, whileErrors
turns them into errors.
Examples
-
Two implementations of the
System.Runtime.CompilerServices.Unsafe
class are provided as examples:- .NET 6 version (compare to the original IL code).
- .NET 9 version, with newer API.
-
Unit tests can also serve as examples of API usage. See verifiable and unverifiable test cases.
-
See also the simple example from above.