【发布时间】:2015-04-22 18:19:46
【问题描述】:
下面的程序导致以下故障:
Field in TypedReferences cannot be static or init only
基于此,明显的解决方法是:
- 移除
readonly修饰符private readonly T _value
但是,以下两个更改也消除了故障:
- 将
struct Data更改为class Data - 将
public int[] Content更改为public int Content
有谁知道 BinaryFormatter 内部发生了什么,允许序列化在案例 #2 和 #3 中继续进行?
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace SerializationStumper {
// *** helper
public static class Serializer {
public static MemoryStream SerializeToStream<T>(T o)
{
var stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, o);
return stream;
}
public static T DeserializeFromStream<T>(MemoryStream stream)
{
IFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
public static T RoundTrip<T>(T v) {
return DeserializeFromStream<T>(SerializeToStream<T>(v));
}
}
// *** set up data structures
[Serializable]
public struct Wrapped<T> {
private readonly T _value;
public Wrapped(T value) {
_value = value;
}
}
[Serializable]
public struct Data {
public int[] Content;
}
// *** Perform test
public class Program {
private static void Main(string[] args)
{
var wrapped = new Wrapped<Data>(new Data { Content = new int[] { 1, 2, 3 } } );
var roundtrip = Serializer.RoundTrip(wrapped);
Console.WriteLine(roundtrip);
}
}
}
【问题讨论】:
-
完整的堆栈跟踪告诉我们代码在这里失败:[ArgumentException: Field in TypedReferences cannot be static or init only.] System.TypedReference.MakeTypedReference(Object target, FieldInfo[] flds) 和其中抛出它的具体检查方法是: if (runtimeFieldInfo.IsInitOnly || runtimeFieldInfo.IsStatic) throw new ArgumentException(Environment.GetResourceString("Argument_TypedReferenceInvalidField"));所以我认为类和结构之间的区别与它们如何通过 ObjectManager 中的解析加载有关。即不同的属性
-
可能是为结构而不是类调用 Serialization.ObjectManager.DoValueTypeFixup。 DoValueTypeFixup 依次调用 TypedReference.MakeTypedReference。我无法逐步浏览源代码,但是如果您加载符号并这样做,它应该会变得清晰(呃)。
标签: c# serialization binary readonly binaryformatter