英文:
Convert class object to byte[]
问题
我正在使用C#编写一个软件,它以原始数据类型组成的泛型类作为输入,然后生成一个字节流。这个字节流必须被发送到PLC缓冲区。
我在StackOverflow上阅读了很多文章,基本上有三种解决方案:
-
使用二进制格式化器。这种解决方案给我带来了一个序列化的二进制流(尝试反序列化方法会返回原始类),但在检查缓冲区时,我发现无法找到我的数据(请参见下面的详细信息)。此外,我有点担心,通过查看Microsoft文档,这个类已经被弃用。
-
使用二进制写入器。这种方法可以正常工作,但由于有很多不同的类声明,我需要使用反射来动态检索每种类型并进行序列化,这对我来说有点太复杂(我把它作为“备用”解决方案)。
-
使用TypeDescriptor来转换对象。这根本不起作用,运行时引擎返回“TypeConverter无法转换X类”。
-
二进制格式化器的代码如下:
TYPE_S_TESTA test = new TYPE_S_TESTA();
test.b_tipo = 54;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter(); // 二进制格式化器已弃用
bf.Serialize(ms, test);
ms.Seek(0, SeekOrigin.Begin);
byte[] test3 = ms.ToArray();
}
要序列化的类定义如下:
[Serializable]
public class TYPE_S_TESTA
{
public short b_tipo;
public char b_modo;
public char b_area;
public char b_sorgente;
public char b_destinatario;
public short w_lunghezza;
public short w_contatore;
public short w_turno;
public short w_tempo;
}
我已经为测试目的在我的类中定义了一个值。我期望得到一个包含'54'的14字节数组(顺便问一下,序列化的顺序是什么?我需要与我的定义完全相同的顺序)。但是,通过调试器在test3缓冲区中看到的是:
_buffer {byte[512]} byte[]
[0] 0 byte
[1] 1 byte
[2] 0 byte
[3] 0 byte
[4] 0 byte
[5] 255 byte
[6] 255 byte
[7] 255 byte
[8] 255 byte
[9] 1 byte
[10] 0 byte
[11] 0 byte
[12] 0 byte
[13] 0 byte
[14] 0 byte
[15] 0 byte
[16] 0 byte
[17] 12 byte
[18] 2 byte
[19] 0 byte
[20] 0 byte
[21] 0 byte
[22] 71 byte
[23] 70 byte
[24] 97 byte
[25] 99 byte
所以,我的'54'没有任何痕迹,而且有一个512字节的缓冲区(为什么这么大?)。
英文:
I'm writing a software in C# which has as input a generic class made by primitive types and should generate a bytestream. This bytestream must be sent to a PLC buffer.
I read so many articles here in StackOverflow which basically go in three solutions:
-
Using binary formatter. This solution brings me a serializated binary stream (trying back Deserialize method returns me the original class) but checking the buffer I discovered that I can't find my data (see details below). Moreover I'm little bit worried by the fact that by checking Microsoft documentation the class is deprecated.
-
Using binary writer. This works correctly, but having a lot of different class declarations I needs to use Reflections in order retrieve dinamically each type and serialize it and it sounds a little bit too complicated to me (I'm leaving it as a "plan b" solution).
-
Using TypeDescriptor to convert the object. It doesn't work at all and Runtime engine returns "TypeConverter' is unable to convert X class"
-
Binary formatter code try is as follows:
TYPE_S_TESTA test = new TYPE_S_TESTA();
test.b_tipo = 54;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter(); // BinaryFormatter is deprecated
bf.Serialize(ms, test);
ms.Seek(0, SeekOrigin.Begin);
byte[] test3 = ms.ToArray();
}
Class to serialize is defined as follows:
[Serializable]
public class TYPE_S_TESTA
{
public short b_tipo;
public char b_modo;
public char b_area;
public char b_sorgente;
public char b_destinatario;
public short w_lunghezza;
public short w_contatore;
public short w_turno;
public short w_tempo;
}
I already defined one value in my class as per test purposes. I expected a 14 bytes array with '54' inside (btw, another question is, what's the serialization order? I need exactly the same order as my definition). What I see with debugger on test3 buffer is instead:
_buffer {byte[512]} byte[]
[0] 0 byte
[1] 1 byte
[2] 0 byte
[3] 0 byte
[4] 0 byte
[5] 255 byte
[6] 255 byte
[7] 255 byte
[8] 255 byte
[9] 1 byte
[10] 0 byte
[11] 0 byte
[12] 0 byte
[13] 0 byte
[14] 0 byte
[15] 0 byte
[16] 0 byte
[17] 12 byte
[18] 2 byte
[19] 0 byte
[20] 0 byte
[21] 0 byte
[22] 71 byte
[23] 70 byte
[24] 97 byte
[25] 99 byte
So, no trace of my 54 and a 512 bytes buffer (why is it so big?).
答案1
得分: 1
你可以这样声明 `TYPE_S_TESTA`:
using System.Runtime.InteropServices
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TYPE_S_TESTA
{
public short b_tipo;
public char b_modo;
public char b_area;
public char b_sorgente;
public char b_destinatario;
public short w_lunghezza;
public short w_contatore;
public short w_turno;
public short w_tempo;
}
你可以将 `TYPE_S_TESTA` 的实例转换为字节数组,方法如下:
TYPE_S_TESTA test = new TYPE_S_TESTA();
test.b_tipo = 54;
int size = Marshal.SizeOf(typeof(TYPE_S_TESTA));
byte[] test3 = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(test, ptr, true);
Marshal.Copy(ptr, test3, 0, size);
<details>
<summary>英文:</summary>
You can declare `TYPE_S_TESTA` as follows:
using System.Runtime.InteropServices
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TYPE_S_TESTA
{
public short b_tipo;
public char b_modo;
public char b_area;
public char b_sorgente;
public char b_destinatario;
public short w_lunghezza;
public short w_contatore;
public short w_turno;
public short w_tempo;
}
You can convert an instance of a `TYPE_S_TESTA` to a byte array like this:
TYPE_S_TESTA test = new TYPE_S_TESTA();
test.b_tipo = 54;
int size = Marshal.SizeOf(typeof(TYPE_S_TESTA));
byte[] test3 = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(test, ptr, true);
Marshal.Copy(ptr, test3, 0, size);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论