Skip to content

Unsafe.OffsetOf to get field offsets in types #43285

@PJB3005

Description

@PJB3005

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 refs 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions