C# 结构中的结构,可以更改内部结构类型
对此没有太多的解释,这就是我所拥有的:C# 结构中的结构,可以更改内部结构类型,c#,struct,C#,Struct,对此没有太多的解释,这就是我所拥有的: public struct PACKET_HEADER { public string computerIp; public string computerName; public string computerCustomName; }; public struct PACKET { public PACKET_HEADER pktHdr;
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;
};
基本上,我希望数据包数据中的数据字段能够是数据文件或数据消息。我知道类型需要更改,但我不知道该做什么,泛型是一种选择吗
最终结果应该是,我可以执行以下任一操作:
pktData.data.fileName
或
pktData.data.message
编辑
我可以做到:
public struct PACKET_DATA
{
public Command command;
public string data;
public DATA_MESSAGE data_message;
public DATA_FILE data_file;
};
只要在我不需要它们的时候,将data_消息或文件设置为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
除了我的序列化程序“试图读取或写入受保护的内存。这通常表明其他内存已损坏”之外,所有内容似乎都正常工作。gunna在发布我的工作解决方案时查看一下:)
编辑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;
}
(反)上述序列化
简单的例子:
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;
packetreturnpacket=(PACKET)PACKET.Deserialize(socketData.dataBuffer,typeof(PACKET));
//获取文件
字符串文件名=returnPacket.pktData.GetData().fileName;
long fileSize=returnPacket.pktData.GetData().fileSize;
一切似乎都很顺利:)您可以使用泛型,但随后一个类型参数将传播到数据包结构,我猜这将使其难以使用,而不是您想要的 在这里使用结构而不是类的目的是什么?是互操作吗?(在这种情况下,互操作场景将指示正确的解决方案)。还是为了避免装箱/堆分配?
public struct PACKET\u数据
public struct PACKET_DATA
{
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;
}
PACKET_DATA packetData = new PACKET_DATA();
packetData.data = new DATA_MESSAGE();
var message = packetData.GetData<DATA_MESSAGE>().message;
{
公共IData数据;
public T GetData(),其中T:IDATA
{
返回(T)数据;
}
}
公共接口IDATA{}
公共结构数据_消息:IDATA
{
公共字符串消息;
}
公共结构数据_文件:IDATA
{
公共字符串文件名;
公共长文件大小;
}
PACKET_DATA packetData=新的PACKET_DATA();
packetData.data=新数据_消息();
var message=packetData.GetData().message;
如何定义两个结构都从中继承的伪接口?当然,这不会解决序列化问题,但正如前面所说的,您可能仍然需要自定义序列化方法
public interface IDataType
{
}
public struct PACKET_DATA
{
public Command command;
public IDataType data;
};
public struct DATA_MESSAGE : IDataType
{
public string message;
};
public struct DATA_FILE : IDataType
{
public string fileName;
public long fileSize;
};
这个问题需要一个明确的答案,所以我将尝试总结: 如果您想将C#数据结构转换为字节数组,可以使用结构和封送,或者使用类(或结构,但为什么要使用)和序列化框架(如
BinaryFormatter
),或者自定义序列化逻辑(如BinaryWriter
)。我们可以就哪一个更好展开讨论,但现在假设我们使用的是结构,我们使用的是封送。尽管我会说,结构是非常有限的,应该主要用于与Win32 API函数的互操作
所以问题是,我们有一个容器结构,它可能包含两种类型的子结构之一。如果你要封送一个结构,像泛型和/或为你的子结构类型使用一个公共接口这样的事情是不会发生的。基本上,您唯一的选择是让容器同时具有structs和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;
};
也就是说,在您的情况下,使用结构和编组只会在您自己的流程中真正起作用,因为您的结构包含字符串。当结构包含指向非固定长度字符串的指针时,这些字符串将分配到其他位置,并且不会成为您复制的字节数组的一部分,只有指向它们的指针才会被分配。您还需要在某个时候调用Marshal.DestroyStructure,使用传递给StructureToPtr的IntPtr来清理这些字符串资源
所以这个故事的寓意是:你能按照你最初的要求制作结构吗。你应该像现在这样使用它们:不。因为你有一个可变大小的数据结构,你正试图通过网络发送(我假设,因为这个结构被称为数据包),所以结构不起作用,你真的需要使用某种序列化框架或自定义序列化逻辑“你可以用泛型来做,但是类型参数会传播到数据包结构中,我猜这会让你很难使用它,而不是你想要的。”是的,我看过了,但它确实变得非常混乱。数据包结构(及其内容)获取序列化并作为字节数组通过网络发送。其目的只是为了在短时间内存储少量信息,我了解到结构比类更适合于此。主要是因为您希望高效序列化吗?如果是这样,最佳方法是编写自定义序列化器。使这些类型类而不是结构(就GC而言)不是很好。只是澄清一下你的编辑:结构,作为值类型,永远不会为空。你需要一个标志来指示哪个成员是有效的。是的,我刚刚意识到它们不能为空。我想有两种类型的数据包,见上文,这会更有意义吗?好的,但请记住反序列化的代码需要确定t他键入。我实际上喜欢你的两个子结构版本,你只需要一个
bool isMessagePacket;
。关于你的内存访问错误,你有什么方法
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;
};