C#序列化失败-解决方法?
以下程序导致以下故障:C#序列化失败-解决方法?,c#,serialization,binary,readonly,binaryformatter,C#,Serialization,Binary,Readonly,Binaryformatter,以下程序导致以下故障: Field in TypedReferences cannot be static or init only 基于此,显而易见的解决方案是: 删除private readonly T\u值上的readonly修饰符 但是,以下两个更改也消除了故障: 将结构数据更改为类数据 将public int[]Content更改为public int Content 有人知道BinaryFormatter的内部发生了什么,允许序列化在第2和第3种情况下继续进行吗 使用系统; 使用
Field in TypedReferences cannot be static or init only
基于此,显而易见的解决方案是:
private readonly T\u值上的readonly
修饰符
public int[]Content
更改为public int Content
使用系统;
使用System.IO;
使用System.Runtime.Serialization;
使用System.Runtime.Serialization.Formatters.Binary;
命名空间序列化程序{
//***助手
公共静态类序列化程序{
公共静态内存流序列化到流(TO)
{
var stream=newmemoryStream();
IFormatter formatter=新的BinaryFormatter();
序列化(流,o);
回流;
}
公共静态T反序列化FromStream(MemoryStream stream)
{
IFormatter formatter=新的BinaryFormatter();
stream.Seek(0,SeekOrigin.Begin);
返回(T)格式化程序。反序列化(流);
}
公共静态T往返(TV){
返回反序列化FromStream(SerializeToStream(v));
}
}
//***设置数据结构
[可序列化]
公共结构包装{
私有只读T_值;
公共包装(T值){
_价值=价值;
}
}
[可序列化]
公共结构数据{
公共内容;
}
//***执行测试
公共课程{
私有静态void Main(字符串[]args)
{
var wrapped=newwrapped(新数据{Content=newint[]{1,2,3});
var roundtrip=Serializer.roundtrip(已包装);
控制台写入线(往返);
}
}
}
既然还没有人接,我就试试看
它可以序列化,但反序列化失败
我不确定这一点,但我怀疑这是因为作为一个结构,反序列化程序不知道这个数组有多大:
public int[] Content;
所以它不知道要读取多少字节来填充数组。
作为一个类,它可能会将长度序列化到数据中
如果将结构和类序列化为不同的文件,它们的内容确实略有不同,序列化类中的一个额外字节是数字3,我猜是数组长度。虽然我还没有研究过二进制输出格式
“修复”可能与此有关,因此反序列化程序将知道数据流中有多少字节组成了数组。不过,我还没有制定出使用它们的有效解决方案
编辑:似乎您无法序列化固定大小的缓冲区,因此请忽略上述内容
所以#2可以工作,因为它将数组长度序列化到数据流中,而#3之所以起作用,是因为在
int
中,数组长度是固定字节大小的。数组长度被序列化到结构和类的流中,因此这不会成为re:#2当数据是类与结构时,文件中的额外长度只是类与结构的头长度之差。i、 e.这适用于结构02000000002000000005,这适用于类0200000000200000000903000000050300000015。如果更改数组中的元素数,则这两个标头都不会更改。包括数组长度在内的信息是为Content属性编码的,它的序列化字节对于struct vs class不会改变。3元素数组的编码如下:07080200000904000000F040000000000300000B和类似的4元素数组0708020000009040000000000F04000000040000000800000000200000003000000040000000B,其中000F04000000300VS000F040000000400具有长度编码,并且在更改结构vs类时不会更改。完整堆栈跟踪告诉我们代码在此处失败:[ArgumentException:TypedReferences中的字段不能是静态的或仅是init。]System.TypedReference.MakeTypedReference(对象目标,FieldInfo[]flds)以及在该方法中引发它的特定检查是:if(runtimeFieldInfo.IsInitOnly | | runtimeFieldInfo.IsStatic)引发新ArgumentException(Environment.GetResourceString(“Argument_TypedReferenceInvalidField”);因此,我认为类和结构之间的差异与如何通过ObjectManager中的解析加载它们有关。i、 不同的属性可能是为结构而不是为类调用Serialization.ObjectManager.DoValueTypeFixup。DoValueTypeFixup依次调用TypedReference.MakeTypedReference。我不能一步一步地浏览源代码,但如果你加载符号并这样做,它应该变得清晰(呃)。
public int[] Content;