C#:循环遍历嵌套结构的成员对象
Posted
技术标签:
【中文标题】C#:循环遍历嵌套结构的成员对象【英文标题】:C#: Looping through member objects of nested structs 【发布时间】:2021-12-27 18:06:42 【问题描述】:大家好,所有 c# 向导!
我需要将(打包的)嵌套结构的所有内存偏移值存储在这些各自的结构中。 到目前为止,循环遍历所有成员都可以正常工作。另外,我得到了适当的内存偏移值。 这个结构装置可能包含几十个结构,最后还有几百个其他成员。 但是我在初始化时做这一切,所以 CPU 性能在这里不会成为问题。
但是:
在这个迭代过程中,我似乎无法访问这些结构的实际实例。事实证明,当我尝试存储这些偏移值时,它们最终不会出现在我需要它们的地方(当然,我需要它们在实例“SomeStruct1”及其包含其他结构实例中,但是调试器清楚地向我显示了初始值 (-1))。
我怀疑“field_info.GetValue”或“obj_type.InvokeMember”不是获取对象引用的正确方法?还有其他方法可以遍历嵌套结构instances吗?
请帮忙!我已经拼命调试和谷歌了三天,但我现在完全没有想法......
感谢您的努力!
-阿尔伯特
PS - 我做这些不寻常的事情的原因: 我通过提到的嵌套结构在两个嵌入式 CPU 内核之间进行通信(两者都是混合 c/c++ 项目)。这就像一个魅力,因为两个内核共享相同的内存,结构所在的位置。
此外,我必须在 c# 主机应用程序和这些嵌入式内核之间进行通信,所以我认为如果我实现这个结构的第三个实例,这可能是一件很巧妙的事情。只有这一次,我显然不能使用共享 RAM。相反,我为数据保存成员实现值设置器和获取器,找出内存偏移量以及数据保存成员的长度,并通过 USB 或以太网将此信息(连同值本身)提供给嵌入式系统 - 所以我的嵌入式系统的“API”将只是一个结构。每次更改结构时,我必须做的唯一维护是:我必须将保存的 .h 文件(嵌入式项目的)复制到 .cs 文件(宿主项目)。 我知道这很疯狂 - 但现在可以了。
感谢您的关注。 -阿尔伯特
这是一个应该编译和执行的简化(错误,见下文)示例(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);
【问题讨论】:
也许你应该描述你想做什么。你做这一切是为了什么。一定有更好的解决方案,C# 从来没有在内存结构中进行字节推送和偏移计数。 你说的“正确的参考”是什么意思?你有结构。他们被装箱了。传递为object
,转换为Interf
...新的引用正在被创建和丢弃。您传递给InitializeOffsets
的原始SomeStruct1
正在被复制;原版不受这一切的影响。改用类。
@nvoigt:我同意,必须有更好的解决方案。好的,我将添加一个说明我为什么这样做。
@madreflection:你是对的。我很难避免复制。不幸的是,我需要结构。
【参考方案1】:
同时我发现了我做错了什么:
-
我必须做拳击,所以我可以在调用初始化函数时使用“ref”:
// instead of this:
SomeStruct1 = new sSomeStruct1 (true);
// i have to do it this way:
object boxed_SomeStruct1 = new sSomeStruct1 (true);
InitializeOffsets (ref boxed_SomeStruct1);
SomeStruct1 = (sSomeStruct1) boxed_SomeStruct1;
-
在“InitializeOffsets”函数中,“field_info.GetValue (obj)”提供了我的成员对象的副本。这就是为什么我必须在 foreach 循环的最后将修改后的副本复制回来:
field_info.SetValue (obj, node_obj);
进行这些更改后,代码将按预期工作。 谢谢你的关注。 -阿尔伯特
【讨论】:
以上是关于C#:循环遍历嵌套结构的成员对象的主要内容,如果未能解决你的问题,请参考以下文章