ILAccess.Fody 0.1.4

dotnet add package ILAccess.Fody --version 0.1.4
                    
NuGet\Install-Package ILAccess.Fody -Version 0.1.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ILAccess.Fody" Version="0.1.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ILAccess.Fody" Version="0.1.4" />
                    
Directory.Packages.props
<PackageReference Include="ILAccess.Fody" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ILAccess.Fody --version 0.1.4
                    
#r "nuget: ILAccess.Fody, 0.1.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ILAccess.Fody@0.1.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ILAccess.Fody&version=0.1.4
                    
Install as a Cake Addin
#tool nuget:?package=ILAccess.Fody&version=0.1.4
                    
Install as a Cake Tool

ILAccess.Fody

Build NuGet package .net License δΈ­ζ–‡

✨ Overview

ILAccess.Fody provides functionality similar to the UnsafeAccessor introduced in .NET 8, but supports older .NET platforms. It is a Fody weaver that injects IL at compile-time, enabling access to private or internal members without runtime reflection. This results in faster access and compile-time safety compared to traditional reflection-based approaches.


πŸš€ Installation

  • Include the Fody and ILAccess.Fody NuGet packages with a PrivateAssets="all" attribute on their <PackageReference /> items. Installing Fody explicitly is needed to enable weaving.

    <PackageReference Include="Fody" Version="..." PrivateAssets="all" />
    <PackageReference Include="ILAccess.Fody" Version="..." PrivateAssets="all" />
    
  • If you already have a FodyWeavers.xml file in the root directory of your project, add the <ILAccess /> tag there. This file will be created on the first build if it doesn't exist:

    <?xml version="1.0" encoding="utf-8" ?>
    <Weavers>
      <ILAccess />
    </Weavers>
    

See Fody usage for general guidelines, and Fody Configuration for additional options.


🧩 Usage Example

You can use ILAccessor to access private fields, methods, or constructors β€” similar to UnsafeAccessor since .NET 8.

public class TestModel
{
    private static int _staticValue = 42;
    private int _value;
    private TestModel(int value) => _value = value;
    private string GetMessage(int code) 
        => $"Current value: {_value}, code: {code}";
    private static string GetStaticMessage(int code) 
        => $"Current static value: {_staticValue}, code: {code}";
}

public static class Accessors
{
    [ILAccessor(ILAccessorKind.Field, Name = "_value")]
    public static extern ref int Value(this TestModel instance);

    [ILAccessor(ILAccessorKind.StaticField, Name = "_staticValue")]
    public static extern ref int StaticValue(TestModel instance);

    [ILAccessor(ILAccessorKind.Method, Name = "GetMessage")]
    public static extern string GetMessage(this TestModel instance, int code);

    [ILAccessor(ILAccessorKind.StaticMethod, Name = "GetStaticMessage")]
    public static extern string GetStaticMessage(TestModel? instance, int code);

    [ILAccessor(ILAccessorKind.Constructor)]
    public static extern TestModel Ctor(int x);
}

internal class Program
{
    private static void Main(string[] args)
    {
        var model = Ctor(100);
        ref var value = ref model.Value();
        Console.WriteLine($"_value: {value}");

        value += 50;
        Console.WriteLine($"_value updated: {value}");

        ref var staticValue = ref StaticValue(model);
        Console.WriteLine($"_staticValue: {staticValue}");
        staticValue += 10;
        Console.WriteLine($"_staticValue updated: {staticValue}");

        var message = model.GetMessage(7);
        Console.WriteLine($"GetMessage: {message}");

        var staticMessage = GetStaticMessage(null, 7);
        Console.WriteLine($"GetStaticMessage: {staticMessage}");

        Console.Read();
    }
}

πŸ› οΈ How It Works

The stub methods in the TestModel are replaced at compile-time with injected IL instructions that directly access the target members.
Below is an example of what the generated IL looks like after weaving:

.method public hidebysig static int32& Value(class ILAccess.Example.TestModel 'instance') cil managed
{
    IL_0000: ldarg.0      // 'instance'
    IL_0001: ldflda       int32 ILAccess.Example.TestModel::_value
    IL_0006: ret
}

.method public hidebysig static int32& StaticValue(class ILAccess.Example.TestModel 'instance') cil managed
{
    IL_0000: ldsflda      int32 ILAccess.Example.TestModel::_staticValue
    IL_0005: ret
}

.method public hidebysig static string GetMessage(class ILAccess.Example.TestModel 'instance', int32 code) cil managed
{
    IL_0000: ldarg.0      // 'instance'
    IL_0001: ldarg.1      // code
    IL_0002: callvirt     instance string ILAccess.Example.TestModel::GetMessage(int32)
    IL_0007: ret
}

.method public hidebysig static string GetStaticMessage(class ILAccess.Example.TestModel 'instance', int32 code) cil managed
{
	IL_0000: ldarg.1      // code
	IL_0001: call         string ILAccess.Example.TestModel::GetStaticMessage(int32)
	IL_0006: ret
}

.method public hidebysig static class ILAccess.Example.TestModel Ctor(int32 x) cil managed
{
	IL_0000: ldarg.0      // x
	IL_0001: newobj       instance void ILAccess.Example.TestModel::.ctor(int32)
	IL_0006: ret
}

These injected method bodies effectively make private and static members accessible in a strongly-typed, reflection-free way.


βš–οΈ Comparison

Feature Reflection UnsafeAccessor ILAccess.Fody
Performance Slow 🐌 Fast πŸš€ Fast πŸš€
Works before .NET 8 βœ… ❌ βœ…
Compile-time validation ❌ ❌ βœ…
AOT Partly supported ⚠️ βœ… βœ…

🧭 Todo

  • Add more test cases.
  • Add more compile-time validation and diagnostic messages.

πŸ“„ License

MIT License β€” see LICENSE for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.4 214 11/7/2025
0.1.3 232 10/30/2025
0.1.2 240 10/29/2025
0.1.1 233 10/28/2025
0.1.0 231 10/26/2025
0.0.8 180 10/26/2025
0.0.7 161 10/25/2025