注意:随着我对该问题的了解更多,这个问题发生了一些变化,因此请完整阅读。我决定保留它的原始形式,因为它更好地描述了问题是如何被发现和最终解决的。
回到我们项目历史的最黑暗深处,当我们没有像我们可能的那样真正了解 C# 或 CLR 时,我们创建了一个类型,我们称之为MyType
. 我们将此类型创建为class
一个引用类型。
然而,很明显MyType
应该是struct
一个值类型,所以我们进行了一些更改以使其如此,一切都很好,直到有一天,我们尝试反序列化一些包含值集合的数据MyType
。嗯,不是真的,因为当它是一个引用类型时,那个集合就是一个引用的集合。现在,当它反序列化时,集合可以很好地反序列化,使用 的默认构造函数MyType
,然后当实际引用反序列化时,它们是孤立的,给我们留下一个空值集合。
因此,我们想,“让我们在加载时将类型映射到引用类型,MyTypeRef
以便引用正确解析,然后转换回我们的真实类型以在执行时和重新序列化期间使用”。所以我们做了(使用我们自己的活页夹),但是可惜,它不起作用,因为现在我们得到一个错误,告诉我们即使我们在and之间进行了隐式转换,MyTypeRef[]
也无法转换为。MyType[]
MyTypeRef
MyType
所以,我们被困住了。我们如何将一个集合序列化为引用类型的集合MyType
以反序列化为值类型的集合MyType
?
更新
一些调查(见下面的评论和代码)表明,新的不可变性质MyType
及其用于ISerializable
序列化的特性导致了真正的问题。我仍然不明白为什么会这样,但是如果我使用private
set 访问器而不是ISerializable
,新的MyType
将加载旧的(请注意,ISerializable
如果我使用它会调用接口,但集合甚至只包含默认值)。
一些代码
// Use a List<T> in a class that also implements ISerializable and
// save an instance of that class with a BinaryFormatter (code omitted)
// Save with this one.
[Serializable]
public class MyType
{
private string test;
public string Test
{
get { return this.test; }
set { this.test = value; }
}
public MyType()
{
}
}
// Load with this one.
[Serializable]
public class MyType : ISerializable
{
private string test;
public string Test
{
get { return this.test; }
set { this.test = value; }
}
public MyType()
{
}
public MyType(SerializationInfo info, StreamingContext context)
{
info.AddValue("test", this.test);
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
this.test = info.GetString("test");
}
}
请注意,加载时,元素都是空值。ISerializable
从第二个定义中删除并加载和所有工作。在加载代码上更改class
为struct
,并且可以看到相同的行为。就好像集合只会使用 set 访问器成功反序列化。
更新二
因此,我发现了问题(请参阅下面的答案),但我怀疑有人会通过阅读我的问题知道答案。我错过了一个重要的细节,当时我什至没有意识到这很重要。我向那些试图提供帮助的人致以最诚挚的歉意。
加载的包含MyType
的集合在 期间立即复制到另一个集合GetObjectData
。下面的答案解释了为什么这很重要。这是上面给出的一些附加示例代码,应该提供一个完整的示例:
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
this.myTypeCollection = new List<MyType>();
var loadedCollection = (List<MyType>)info.GetValue(
"myTypeCollection",
typeof(List<MyType>));
this.myTypeCollection.AddRange(loadedCollection);
}