Skip to content

Instantly share code, notes, and snippets.

@gotmachine
Last active July 13, 2025 18:33
Show Gist options
  • Save gotmachine/d6121bd96de68b6bcd52ae2abef203b9 to your computer and use it in GitHub Desktop.
Save gotmachine/d6121bd96de68b6bcd52ae2abef203b9 to your computer and use it in GitHub Desktop.
Small helper class for IL-emitting anonymous field getter/setter delegates
public struct MyStruct
{
private static int staticField;
private int field;
}
public class MyClass
{
private static int staticField;
private int field;
}
FieldInfo myStructStaticField = typeof(MyStruct).GetField("staticField", BindingFlags.Static | BindingFlags.NonPublic);
FieldAccess.StaticSetter<int> MyStructStaticFieldSetter = FieldAccess.EmitStaticSetter<MyStruct, int>(myStructStaticField);
FieldAccess.StaticGetter<int> MyStructStaticFieldGetter = FieldAccess.EmitStaticGetter<MyStruct, int>(myStructStaticField);
MyStructStaticFieldSetter(42);
int structStaticValue = MyStructStaticFieldGetter();
FieldInfo myStructField = typeof(MyStruct).GetField("field", BindingFlags.Instance | BindingFlags.NonPublic);
FieldAccess.StructSetter<MyStruct, int> MyStructFieldSetter = FieldAccess.EmitStructSetter<MyStruct, int>(myStructField);
FieldAccess.InstanceGetter<MyStruct, int> MyStructFieldGetter = FieldAccess.EmitInstanceGetter<MyStruct, int>(myStructField);
MyStruct myStruct = new MyStruct();
MyStructFieldSetter(ref myStruct, 42);
int structValue = MyStructFieldGetter(myStruct);
FieldInfo myClassStaticField = typeof(MyClass).GetField("staticField", BindingFlags.Static | BindingFlags.NonPublic);
FieldAccess.StaticSetter<int> MyClassStaticFieldSetter = FieldAccess.EmitStaticSetter<MyClass, int>(myClassStaticField);
FieldAccess.StaticGetter<int> MyClassStaticFieldGetter = FieldAccess.EmitStaticGetter<MyClass, int>(myClassStaticField);
MyClassStaticFieldSetter(42);
int classStaticValue = MyClassStaticFieldGetter();
FieldInfo myClassField = typeof(MyClass).GetField("field", BindingFlags.Instance | BindingFlags.NonPublic);
FieldAccess.ClassSetter<MyClass, int> MyClassFieldSetter = FieldAccess.EmitClassSetter<MyClass, int>(myClassField);
FieldAccess.InstanceGetter<MyClass, int> MyClassFieldGetter = FieldAccess.EmitInstanceGetter<MyClass, int>(myClassField);
MyClass myClass = new MyClass();
MyClassFieldSetter(myClass, 42);
int classValue = MyClassFieldGetter(myClass);
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace ReflectionUtils
{
/// <summary>
/// A static helper for IL-emitting anonymous field getters and setters. <para/>
/// Provide convenient, type-safe and much faster access to non-public fields than using the <see cref="FieldInfo.GetValue(object)"/> or <see cref="FieldInfo.SetValue(object, object)"/> methods.<para/>
/// </summary>
public static class FieldAccess
{
/// <summary>
/// A getter for a static field.
/// </summary>
/// <typeparam name="TField">The type of the field</typeparam>
/// <returns>The value of the field.</returns>
public delegate TField StaticGetter<out TField>();
/// <summary>
/// Emit a delegate for retrieving the value of the static <paramref name="field"/> of type <typeparamref name="TField"/> on the <typeparamref name="TTarget"/> type.
/// </summary>
public static StaticGetter<TField> EmitStaticGetter<TTarget, TField>(FieldInfo field)
{
return (StaticGetter<TField>)EmitGetter(field, typeof(TTarget), typeof(TField), typeof(StaticGetter<TField>), true);
}
/// <summary>
/// A getter for an instance field.
/// </summary>
/// <typeparam name="TTarget">The type declaring the field</typeparam>
/// <typeparam name="TField">The type of the field</typeparam>
/// <param name="target">The <typeparamref name="TTarget"/> instance to retrieve the field from.</param>
/// <returns>The value of the field.</returns>
public delegate TField InstanceGetter<in TTarget, out TField>(TTarget target);
/// <summary>
/// Emit a delegate for retrieving the value of <paramref name="field"/> of type <typeparamref name="TField"/> on an instance of type <typeparamref name="TTarget"/>.
/// </summary>
public static InstanceGetter<TTarget, TField> EmitInstanceGetter<TTarget, TField>(FieldInfo field)
{
return (InstanceGetter<TTarget, TField>)EmitGetter(field, typeof(TTarget), typeof(TField), typeof(InstanceGetter<TTarget, TField>), false);
}
private static Delegate EmitGetter(FieldInfo field, Type declaringType, Type fieldType, Type delegateType, bool isStatic)
{
if (!field.FieldType.IsAssignableFrom(fieldType))
throw new ArgumentException($"Type {fieldType} cannot be assigned to type {field.FieldType}");
if (!field.DeclaringType.IsAssignableFrom(declaringType))
throw new ArgumentException($"Type {declaringType} cannot be assigned to type {field.DeclaringType}");
if (isStatic != field.IsStatic)
throw new ArgumentException($"Field {field.Name} {(field.IsStatic ? "is" : "isn't")} static");
string methodName = declaringType.FullName + ".get_" + field.Name;
DynamicMethod getterMethod = new DynamicMethod(methodName, fieldType, isStatic ? null : new Type[] { declaringType }, true);
ILGenerator gen = getterMethod.GetILGenerator();
if (isStatic)
{
gen.Emit(OpCodes.Ldsfld, field);
}
else
{
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, field);
}
gen.Emit(OpCodes.Ret);
return getterMethod.CreateDelegate(delegateType);
}
/// <summary>
/// A setter for a static field.
/// </summary>
/// <typeparam name="TField">The type of the field</typeparam>
/// <param name="value">The value to assign to the field.</param>
public delegate void StaticSetter<in TField>(TField value);
/// <summary>
/// Emit a delegate for setting the value of the static <paramref name="field"/> of type <typeparamref name="TField"/> on the type <typeparamref name="TTarget"/>.
/// </summary>
public static StaticSetter<TField> EmitStaticSetter<TTarget, TField>(FieldInfo field)
{
return (StaticSetter<TField>)EmitSetter(field, typeof(TTarget), typeof(TField), typeof(StaticSetter<TField>), true);
}
/// <summary>
/// A setter for a class instance field.
/// </summary>
/// <typeparam name="TTarget">The class declaring the field</typeparam>
/// <typeparam name="TField">The type of the field</typeparam>
/// <param name="target">The <typeparamref name="TTarget"/> instance to assign the field on.</param>
/// <param name="value">The value to assign to the field.</param>
public delegate void ClassSetter<in TTarget, in TField>(TTarget target, TField value) where TTarget : class;
/// <summary>
/// Emit a delegate for setting the value of the <paramref name="field"/> of type <typeparamref name="TField"/> on the instance of a class of type <typeparamref name="TTarget"/>.
/// </summary>
public static ClassSetter<TTarget, TField> EmitClassSetter<TTarget, TField>(FieldInfo field) where TTarget : class
{
return (ClassSetter<TTarget, TField>)EmitSetter(field, typeof(TTarget), typeof(TField), typeof(ClassSetter<TTarget, TField>), false);
}
/// <summary>
/// A setter for a struct instance field.
/// </summary>
/// <typeparam name="TTarget">The struct declaring the field</typeparam>
/// <typeparam name="TField">The type of the field</typeparam>
/// <param name="target">The <typeparamref name="TTarget"/> instance to assign the field on.</param>
/// <param name="value">The value to assign to the field.</param>
public delegate void StructSetter<TTarget, in TField>(ref TTarget target, TField value) where TTarget : struct;
/// <summary>
/// Emit a delegate for setting the value of the <paramref name="field"/> of type <typeparamref name="TField"/> on the instance of a struct of type <typeparamref name="TTarget"/>.
/// </summary>
public static StructSetter<TTarget, TField> EmitStructSetter<TTarget, TField>(FieldInfo field) where TTarget : struct
{
return (StructSetter<TTarget, TField>)EmitSetter(field, typeof(TTarget), typeof(TField), typeof(StructSetter<TTarget, TField>), false);
}
private static Delegate EmitSetter(FieldInfo field, Type declaringType, Type fieldType, Type delegateType, bool isStatic)
{
if (!field.FieldType.IsAssignableFrom(fieldType))
throw new ArgumentException($"Type {fieldType} cannot be assigned to type {field.FieldType}");
if (!field.DeclaringType.IsAssignableFrom(declaringType))
throw new ArgumentException($"Type {declaringType} cannot be assigned to type {field.DeclaringType}");
if (isStatic != field.IsStatic)
throw new ArgumentException($"Field {field.Name} {(field.IsStatic ? "is" : "isn't")} static");
string methodName = declaringType.FullName + ".set_" + field.Name;
Type[] paramTypes;
if (isStatic)
paramTypes = new Type[] { fieldType };
else
paramTypes = new Type[] { declaringType.IsValueType ? declaringType.MakeByRefType() : declaringType, fieldType };
DynamicMethod setterMethod = new DynamicMethod(methodName, null, paramTypes, true);
ILGenerator gen = setterMethod.GetILGenerator();
if (field.IsStatic)
{
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Stsfld, field);
}
else
{
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Stfld, field);
}
gen.Emit(OpCodes.Ret);
return setterMethod.CreateDelegate(delegateType);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment