0

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.

Tomingsun
  • 129
  • 1
  • 11
  • Why would you ever need to do this? And what's wrong with your second option? – Charlieface Aug 25 '23 at 12:52
  • 1. Why to do this: I'm working with Modbus communication, and need to write a value specifically to the modbus registers. Anyway it is required by my colleague. 2. What's wrong: nothing wrong, just wonder if there is a better way. – Tomingsun Aug 25 '23 at 12:55

1 Answers1

0

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

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • What do you mean by "cached reflection"? – Tomingsun Aug 25 '23 at 13:10
  • @Tomingsun reflection in general considered to be relatively slow so in quite a lot of scenarios you might want to perform some caching (though you should check if perfromance is "good enough" in the place). There are several techniques which could be used, in this case you might just maintain a concurrent dictionary from type+path to the offset, or you can use the generic approach to prebuild some info - like [here](https://stackoverflow.com/a/62454454/2501279). – Guru Stron Aug 25 '23 at 13:27