-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Background and Motivation
We wanted to quickly set attribute-tagged fields in user defined types at runtime. The fastest and most flexible way to do this would be various Unsafe
APIs like AddByteOffset
and As
to get ref
s to the field and to then set them (obviously caching the field offsets ahead of time). The problem is that it's kind of extremely annoying to get the actual offset of individual fields: the best way I could figure out is using DynamicMethod
to generate a tiny method that returns a ref
to the field or the offset directly (because there is no FieldInfo.GetValueRef
or something), then to Unsafe.ByteOffset<T>
it.
So I simply propose an API that gets the in-memory offset of a field from the object's memory layout.
Proposed API
namespace System.Runtime.CompilerServices
{
public class Unsafe
{
public int OffsetOf<T>(string fieldName);
public int OffsetOf(Type t, string fieldName);
public int OffsetOf(FieldInfo field);
}
}
Usage Example
private static void SetField<T>(object o, int offset, T value)
{
// or some better way to get a base ref to the class, see below in "nuisances".
var asDummy = Unsafe.As<FieldOffsetDummy>(o);
ref var @ref = ref Unsafe.Add(ref asDummy.A, offset);
ref var oRef = ref Unsafe.As<byte, T>(ref @ref);
oRef = value;
}
private sealed class FieldOffsetDummy
{
public byte A;
}
var offset = Unsafe.OffsetOf(typeof(Foo), "Bar");
var foo = new Foo();
SetField(foo, offset, "hello");
Some nuisances
There isn't really a "clean" way to get a base reference this field offset can be used with. You can define a new class with a single byte
field and then get a ref to that (after Unsafe.As
) but that's far from clear or obvious.
So maybe an API to actually fetch the base reference for an object would go along with this aswell.