Have the same confusion as commented in this answer.
Quotes from CleanCoder:
Can Marshal.OffsetIf be used for fields/props in structs of structs? How this needs to be named? lets say for: Struct1.Struct2.Prop1 Whats the Identifier for Prop1 in Strct1? I want to get the unmanaged offset of a member, which is a child struct's member inside a parent struct. To be clear: a nested member's offset relative to the topmost struct.
I tried the offset2
method (see code below) and it can give me the correct offset, but I wonder if there is a better way?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
struct Address
{
public int Building;
public int Room;
}
struct Person
{
public int Age;
public int Height;
public Address Addr;
}
class OffsetTest
{
public static void CalOffset()
{
// OK
int offset1 = (int)Marshal.OffsetOf(typeof(Person), nameof(Person.Addr));
// Ok, manual add offsets (recursively if nested layer is deeper)
int offset2 = (int)Marshal.OffsetOf(typeof(Person), nameof(Person.Addr)) + (int)Marshal.OffsetOf(typeof(Address), nameof(Address.Room));
// Exception as expected: System.ArgumentException:“Field passed in is not a marshaled member of the type 'Person'. Arg_ParamName_Name”
int offset3 = (int)Marshal.OffsetOf(typeof(Person), nameof(Person.Addr.Room));
// Exception, too
int offset4 = (int)Marshal.OffsetOf(typeof(Person), "Addr.Room");
}
}
In C++, I'll consider create an object and calculate the offset by subtracting addresses directly, but in C# I don't know how to do it.
Can
Marshal.OffsetOf
be used for fields/props in structs of structs? How this needs to be named?
No. It accepts field name which should be present in the provided type, not a path. From Marshal.OffsetOf
docs:
Parameters
fieldName
String
The name of the field in the T type.
So you will need to calculate the offset manually (as you do in " manual add offsets (recursively if nested layer is deeper)"). If needed you can wrap it into some convenient (extension) method which will accept "path" and use some cached reflection to determine the offset.
P.S.
Note that nameof(Person.Addr.Room)
is "Room"
.