The below answer describes how to obtain a managed referenced to a field using the "ref return" feature in C# 7.0:
https://stackoverflow.com/a/45046664/425678
Based on this brilliant answer we can modify the function create_refgetter
to obtain an unmanaged pointer. This makes use of the little known function __makeref which is required when working with generic types (detailed explanation)
This function is then wrapped with the function GetAddressOf
which allows calls without specifying the generic types.
static IntPtr GetAddressOf(object pinned_object, string field_name)
{
var fi_val = pinned_object.GetType().GetField(field_name);
var mi_all = typeof(Program).GetMethod("create_refgetter", BindingFlags.Static | BindingFlags.Public);
var mi_generic = mi_all.MakeGenericMethod(pinned_object.GetType(), fi_val.FieldType);
var ptr = (IntPtr) mi_generic.Invoke(null, new object[] {pinned_object, field_name });
return ptr;
}
https://stackoverflow.com/a/45046664/425678
public delegate ref U RefGetter<T, U>(T obj);
public static IntPtr create_refgetter<T, U>(object obj,string s_field)
{
const BindingFlags bf = BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.DeclaredOnly;
var fi = typeof(T).GetField(s_field, bf);
if (fi == null)
throw new MissingFieldException(typeof(T).Name, s_field);
var s_name = "__refget_" + typeof(T).Name + "_fi_" + fi.Name;
// workaround for using ref-return with DynamicMethod:
// a.) initialize with dummy return value
var dm = new DynamicMethod(s_name, typeof(U), new[] { typeof(T) }, typeof(T), true);
// b.) replace with desired 'ByRef' return value
dm.GetType().GetField("m_returnType", bf).SetValue(dm, typeof(U).MakeByRefType());
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, fi);
il.Emit(OpCodes.Ret);
RefGetter<T, U> ref_getter = (RefGetter<T, U>)dm.CreateDelegate(typeof(RefGetter<T, U>));
unsafe
{
TypedReference t_ref = __makeref(ref_getter((T)obj));
IntPtr ptr = *((IntPtr*)&t_ref);
return ptr;
}
}
}
Exmaple:
class Example // this class is defined in a different assembly and is not known at compile time
{
public double foo;
}
static void Main(string[] args)
{
Example obj = new Example();
obj.foo = 123;
var hdl = GCHandle.Alloc(obj);
unsafe
{
IntPtr foo_add = GetAddressOf(obj, "foo");
double* ptr = (double*) foo_add;
Console.WriteLine("Current Value: {0}", *ptr);
*ptr = 4;
Console.WriteLine("Updated Value: {0}", obj.foo);
}
hdl.Free();
Console.ReadLine();
}
Example Output:
Current Value: 123
Updated Value: 4