【发布时间】:2010-12-20 05:30:33
【问题描述】:
对此没有太多解释,这就是我所拥有的:
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.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_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
一切似乎都在工作,除了我的序列化程序正在“尝试读取或写入受保护的内存。这通常表明其他内存已损坏”。 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;
}
如何创建一个新的数据包(可能可以合并在一起):
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;
一切似乎都很好,花花公子:)
【问题讨论】:
-
只是对您的编辑的澄清:作为值类型的结构永远不会为空。您需要一个标志来指示哪个成员是有效的。
-
是的,我刚刚意识到它们不能为空。我想有两种类型的数据包,见上文,这更有意义吗?
-
好的,但请记住反序列化的代码需要确定类型。我真的很喜欢你的两个子结构版本,你只需要一个
bool isMessagePacket;。 -
另外关于您的内存访问错误,您使用什么方法将字节数组转换为结构,反之亦然?由于您的结构已经包含字符串,这是一个类引用,因此没有内联存储在结构中,我不确定您为什么要使用结构。您也可以只使用类,用 [Serializable] 标记整个事物并使用 BinaryFormatter 进行序列化。
-
@Paul 看看 Edit 5,嗯,课程似乎开始变得更好了