我正在做一些C IO工作,我想从几个类导入/导出数据。
经过一段时间的寻找,似乎系列化是非常接近我想要的。
但是,有一个问题。我有一个xml文件,它描述了某个类(我将称之为ValueWithId
)的成员,这些成员聚集在一个类中,为了解决这个问题,我将调用该类。CollectionOfValuesWithId
是一个包含名为ValueWithId
的成员的类,该成员是唯一的。每个string
只有一个ShortName
,所有ShortName
都有一个非空ValueWithId
。ValueWithId
包含一个函数,用于查找具有给定ShortName
的CollectionOfValuesWithId
。
序列化时,我不想在输出文件中存储ValueWithId
或ShortName
。相反,我只想将ValueWithId
存储在文件中。
到目前为止,一切都好。我只需要使用CollectionOfValuesWithId
。
问题在于反序列化。一些google建议,要从文件中读取数据,可以这样做:
public SomeClassThatUsesValueWithId(SerializationInfo info, StreamingContext ctxt)
{
string name = (string)info.GetValue("ValueWithId", typeof(string));
}
但是,字符串不足以恢复
ShortName
实例。我还需要SerializationInfo.AddValue("ValueWithId", MyValueWIthId.ShortName)
。我想要这样的东西:public SomeClassThatUsesValueWithId(SerializationInfo info,
StreamingContext ctxt, CollectionOfValuesWithId extraParameter)
换句话说,我需要向反序列化构造函数传递额外的数据。有人知道怎么做或者有其他的选择吗?
最佳答案
我想出来了。重要的是StreamingContext
。
这个类有一个名为Context
的属性(可以在构造函数参数additional
中设置)。
从MSDN:
额外的
类型:system.object
任何与
精简上下文。此信息可用于任何对象
实现ISerializable或任何序列化代理项。大多数用户都会
不需要设置此参数。
下面是一些关于如何做到这一点的示例代码(在mono上测试过,但我认为它应该在windows上工作):
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public class ValueWithId
{
public string ShortName;
public string ActualValue;
public ValueWithId(string shortName, string actualValue)
{
ShortName = shortName;
ActualValue = actualValue;
}
public override string ToString()
{
return ShortName + "->" + ActualValue;
}
}
public class CollectionOfValuesWithId
{
private IList<ValueWithId> Values = new List<ValueWithId>();
public void AddValue(ValueWithId val)
{
Values.Add(val);
}
public ValueWithId GetValueFromId(string id)
{
foreach (var value in Values)
if (value.ShortName == id)
return value;
return null;
}
}
[Serializable]
public class SomeClassThatUsesValueWithId : ISerializable
{
public ValueWithId Val;
public SomeClassThatUsesValueWithId(ValueWithId val)
{
Val = val;
}
public SomeClassThatUsesValueWithId(SerializationInfo info, StreamingContext ctxt)
{
string valId = (string)info.GetString("Val");
CollectionOfValuesWithId col = ctxt.Context as CollectionOfValuesWithId;
if (col != null)
Val = col.GetValueFromId(valId);
}
public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
{
//Store Val.ShortName instead of Val because we don't want to store the entire object
info.AddValue("Val", Val.ShortName);
}
public override string ToString()
{
return "Content="+Val;
}
}
class MainClass
{
public static void Main(string[] args)
{
CollectionOfValuesWithId col = new CollectionOfValuesWithId();
col.AddValue(new ValueWithId("foo", "bar"));
SomeClassThatUsesValueWithId sc = new SomeClassThatUsesValueWithId(col.GetValueFromId("foo"));
BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File, col));
using (var stream = new FileStream("foo", FileMode.Create))
{
bf.Serialize(stream, sc);
}
col.GetValueFromId("foo").ActualValue = "new value";
using (var stream2 = new FileStream("foo", FileMode.Open))
{
Console.WriteLine(bf.Deserialize(stream2));
}
}
}
我得到的结果是:
Content=foo->new value
这正是我想要的。