将类对象转换为字节数组

huangapple go评论65阅读模式
英文:

Convert class object to byte[]

问题

我正在使用C#编写一个软件,它以原始数据类型组成的泛型类作为输入,然后生成一个字节流。这个字节流必须被发送到PLC缓冲区。

我在StackOverflow上阅读了很多文章,基本上有三种解决方案:

  1. 使用二进制格式化器。这种解决方案给我带来了一个序列化的二进制流(尝试反序列化方法会返回原始类),但在检查缓冲区时,我发现无法找到我的数据(请参见下面的详细信息)。此外,我有点担心,通过查看Microsoft文档,这个类已经被弃用。

  2. 使用二进制写入器。这种方法可以正常工作,但由于有很多不同的类声明,我需要使用反射来动态检索每种类型并进行序列化,这对我来说有点太复杂(我把它作为“备用”解决方案)。

  3. 使用TypeDescriptor来转换对象。这根本不起作用,运行时引擎返回“TypeConverter无法转换X类”。

  4. 二进制格式化器的代码如下:

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:

  1. 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.

  2. 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).

  3. Using TypeDescriptor to convert the object. It doesn't work at all and Runtime engine returns "TypeConverter' is unable to convert X class"

  4. 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);

huangapple
  • 本文由 发表于 2023年2月18日 00:41:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75487007.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定