mardi 16 novembre 2021

C#: Looping through member objects of nested structs

Hi all you c# wizards!

I need to store all the memory offset values of (packed) nested structs within these respective structs. Recusively looping through all the members works fine so far. Also, i get the appropriate memory offset values. This struct contraption might contain several dozends of structs, and several hundreds of other members in the end. But i do this whole thing at initialization time, so CPU performance won't be an issue here.


But:

In this iteration process, it seems i have trouble accessing the actual instances of those structs. As it turns out, when i try to store these offset values, they don't end up where i need them (of course, i need them in the instance "SomeStruct1" and its containing other struct instances, but the debugger clearly shows me the init values (-1)).

I suspect "field_info.GetValue" or "obj_type.InvokeMember" is not the proper thing to get the object reference? Is there any other way to loop through nested struct instances?

Please help! I've desperately debugged and googled for three days, but i'm so out of ideas now...

Thanks for your efforts!

-Albert


This is a simplified example that should compile and execute (WinForms, c#7.3):

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace CodingExample
{
    public interface Interf
    {
        Int32   Offset  {get; set; }
    }

    [StructLayout (LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct sSomeStruct2 : Interf
    {
        public sSomeStruct2 (bool dummy)
        {
            Offset      = -1;
            SomeMember3 = 0;
        }
        public Int32    Offset  {get; set; }
    
        public Int32    SomeMember3;
        // much more various-typed members (e. g. nested structs)...
    }

    [StructLayout (LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct sSomeStruct1 : Interf
    { 
        public sSomeStruct1 (bool dummy)
        {
            Offset      = -1;
            SomeMember1 = 0;
            SomeStruct2 = new sSomeStruct2 (true);
            SomeMember2 = 0;
        }
        public Int32        Offset  {get; set; }

        public Int32        SomeMember1;
        public sSomeStruct2 SomeStruct2;
        public Int16        SomeMember2;
        // much more various-typed members...
    }

    public partial class Form1 : Form
    {
        void InitializeOffsets (object obj)
        {
            Console.WriteLine ("obj: {0}", obj);

            Type obj_type   = obj.GetType ();

            foreach (FieldInfo field_info in obj_type.GetFields ())
            { 
                string field_name   = field_info.Name;
                Int32 offset        = (Int32) Marshal.OffsetOf (obj_type, field_name);
                Type field_type     = field_info.FieldType;
                bool is_leafe       = field_type.IsPrimitive;

// none of theses three options seem to give me the right reference:
//                object node_obj     = field_info.GetValue (obj);
//                object node_obj     = field_info.GetValue (null);
                object node_obj     = obj_type.InvokeMember (field_name, BindingFlags.GetField, null, obj, null);

                Console.WriteLine ("field: {0}; field_type: {1}; is_leafe: {2}; offset: {3}", field_name, field_type, is_leafe, offset); 

                if (! is_leafe)
                {
// this writes not as expected:                    
                    (node_obj as Interf).Offset = offset;
    
                    InitializeOffsets (node_obj);
                }
            }
        }

        sSomeStruct1 SomeStruct1; 

        public Form1 ()
        {
            InitializeComponent ();

            SomeStruct1 = new sSomeStruct1 (true);

            InitializeOffsets (SomeStruct1);
        }
    }
}




Aucun commentaire:

Enregistrer un commentaire