gpt4 book ai didi

c# - Struct inside Struct,能够改变内部Struct类型

转载 作者:行者123 更新时间:2023-12-02 18:17:17 32 4
gpt4 key购买 nike

对此没有太多解释,这就是我所拥有的:

public struct PACKET_HEADER
{
public string computerIp;
public string computerName;
public string computerCustomName;
};

public struct PACKET
{
public PACKET_HEADER pktHdr;
public PACKET_DATA pktData;
};


public struct PACKET_DATA
{
public Command command;
public string data;
};

public struct DATA_MESSAGE
{
public string message;
};

public struct DATA_FILE
{
public string fileName;
public long fileSize;
};

基本上我希望 PACKET_DATA 中的数据字段能够是 DATA_FILE 或 DATA_MESSAGE。我知道类型需要更改,但我不知道要更改什么,泛型是一个选项吗?

最终结果应该是这样我可以做:

pktData.data.文件名或者pktData.data.message

编辑

我可以做:

public struct PACKET_DATA
{
public Command command;
public string data;
public DATA_MESSAGE data_message;
public DATA_FILE data_file;
};

当我不需要它们时,只需将 data_message 或文件设置为 null 即可?这将如何影响序列化/字节数组和发送的数据。如果我使用类,我不会遇到同样的问题

编辑2

public struct PACKET_MESSAGE
{
public PACKET_HEADER pktHdr;
public Command command;
public DATA_MESSAGE pktData;
};

public struct PACKET_FILE
{
public PACKET_HEADER pktHdr;
public Command command;
public DATA_FILE pktData;
};

编辑3

我有一个可以与我的原始示例配合使用的灭菌器和反灭菌器,如果没有任何问题,那么实际的序列化就完成了。

编辑4

一切似乎都正常,除了我的序列化器收到“尝试读取或写入 protected 内存。这通常表明其他内存已损坏”。发布我的工作解决方案时,请看看它:)

编辑 5

    public static byte[] Serialize(object anything)
{
int rawsize = Marshal.SizeOf(anything);
byte[] rawdatas = new byte[rawsize];
GCHandle handle = GCHandle.Alloc(rawdatas, GCHandleType.Pinned);
IntPtr buffer = handle.AddrOfPinnedObject();
Marshal.StructureToPtr(anything, buffer, false);
handle.Free();
return rawdatas;
}

public static object Deserialize(byte[] rawdatas, Type anytype)
{
int rawsize = Marshal.SizeOf(anytype);
if (rawsize > rawdatas.Length)
return null;
GCHandle handle = GCHandle.Alloc(rawdatas, GCHandleType.Pinned);
IntPtr buffer = handle.AddrOfPinnedObject();
object retobj = Marshal.PtrToStructure(buffer, anytype);
handle.Free();
return retobj;
}

最终

结构:

public struct PACKET_HEADER
{
public string computerIp;
public string computerName;
public string computerCustomName;
};

public struct PACKET
{
public PACKET_HEADER pktHdr;
public PACKET_DATA pktData;
};

public struct PACKET_DATA
{
public Command command;
public IDATA data;
public T GetData<T>() where T : IDATA
{
return (T)(data);
}
}

public interface IDATA { }

public struct DATA_MESSAGE : IDATA
{
public string message;
}

public struct DATA_FILE : IDATA
{
public string fileName;
public long fileSize;
}

如何创建一个新的数据包(可能可以组合在一起):

    public static PACKET CreatePacket(Command command)
{
PACKET packet;
packet.pktHdr.computerIp = Settings.ComputerIP;
packet.pktHdr.computerName = Settings.ComputerName;
packet.pktHdr.computerCustomName = Settings.ComputerCustomName;

packet.pktData.command = command;
packet.pktData.data = null;

return packet;
}

public static PACKET CreatePacket(Command command, DATA_MESSAGE data_message)
{
PACKET packet;
packet.pktHdr.computerIp = Settings.ComputerIP;
packet.pktHdr.computerName = Settings.ComputerName;
packet.pktHdr.computerCustomName = Settings.ComputerCustomName;

packet.pktData.command = command;
packet.pktData.data = data_message;

return packet;
}

public static PACKET CreatePacket(Command command, DATA_FILE data_file)
{
PACKET packet;
packet.pktHdr.computerIp = Settings.ComputerIP;
packet.pktHdr.computerName = Settings.ComputerName;
packet.pktHdr.computerCustomName = Settings.ComputerCustomName;

packet.pktData.command = command;
packet.pktData.data = data_file;

return packet;
}

上面的(de)序列化。

简单的例子:

PACKET packet = Packet.CreatePacket(command, data_file);
byte[] byData = Packet.Serialize(packet);

另一端:

PACKET returnPacket = (PACKET)Packet.Deserialize(socketData.dataBuffer, typeof(PACKET));
// Get file
string fileName = returnPacket.pktData.GetData<DATA_FILE>().fileName;
long fileSize = returnPacket.pktData.GetData<DATA_FILE>().fileSize;

一切似乎都进展顺利:)

最佳答案

这个问题需要一个明确的答案,所以我尝试总结一下:

如果您想采用 C# 数据结构并将其转换为字节数组,您可以使用结构和编码(marshal)处理,或者使用类(或结构,但为什么要这样做)和序列化框架(如 BinaryFormatter),或自定义序列化逻辑(如 BinaryWriter)。我们可以争论哪个更好,但现在假设我们使用结构,并且使用编码(marshal)处理。尽管我会说,该结构非常有限,并且应该主要在与 Win32 API 函数进行互操作时使用。

所以问题是,我们有一个容器结构,它可能包含两种类型的子结构之一。如果您要编码一个结构,那么像泛型和/或为您的子结构类型使用通用接口(interface)之类的事情将不会成功。基本上,您唯一的选择是让容器具有两个结构和一个 bool 标志,指示要使用哪个结构。这样做的缺点是会增加数据包的大小,因为您还要发送未使用的子结构。

在本例中,结果如下所示:

public struct PACKET_DATA
{
public Command command;
public string data;
public bool is_message_packet;
public DATA_MESSAGE data_message;
public DATA_FILE data_file;
};

也就是说,在您的情况下,使用结构和编码只能在您自己的进程中真正起作用,因为您的结构包含字符串。当结构体包含指向非固定长度字符串的指针时,这些字符串将被分配到其他地方,并且不会成为您复制的字节数组的一部分,只有指向它们的指针才会成为。您还需要在某个时候使用传递给 StructureToPtr 的 IntPtr 调用 Marshal.DestroyStructure,以便清理这些字符串资源。

所以这个故事的寓意是:你能否制作出能够完成你最初要求的操作的结构:是的。您是否应该像现在这样使用它们:不。因为您有一个可变大小的数据结构,您试图通过网络发送(我认为该结构称为 PACKET),所以结构将不起作用,您确实需要使用某种序列化框架或自定义序列化逻辑。

关于c# - Struct inside Struct,能够改变内部Struct类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4487155/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com