我正在做一些 C# IO 工作,我想从几个类中导入/导出数据。 找了一段时间,好像连载挺接近我想要的。
但是,有一个问题。我有一个 XML 文件,它描述了某个类的成员(我将其称为 ValueWithId
),这些成员聚集在一个类中,我将调用 CollectionOfValuesWithId
用于这个问题。
ValueWithId
是一个包含名为 ShortName
的 string
成员的类,它是唯一的。每个 ValueWithId
只有一个 ShortName
,所有 ValueWithId
都有一个非空的 ShortName
。 CollectionOfValuesWithId
包含一个函数,用于查找具有给定 ShortName
的 ValueWithId
。
序列化时,我不想希望在输出文件中存储ValueWithId
或CollectionOfValuesWithId
。相反,我只想将 ShortName
存储在文件中。
到目前为止,一切都很好。我只需要使用 SerializationInfo.AddValue("ValueWithId", MyValueWIthId.ShortName)
。
问题来自反序列化。一些谷歌搜索表明,要从文件中读取数据,可以这样做:
public SomeClassThatUsesValueWithId(SerializationInfo info, StreamingContext ctxt)
{
string name = (string)info.GetValue("ValueWithId", typeof(string));
}
但是,该字符串不足以恢复 ValueWithId
实例。我还需要 CollectionOfValuesWithId
。我想要这样的东西:
public SomeClassThatUsesValueWithId(SerializationInfo info,
StreamingContext ctxt, CollectionOfValuesWithId extraParameter)
换句话说,我需要将额外的数据传递给反序列化构造函数。有谁知道这样做的任何方法或任何替代方法?
最佳答案
我想通了。执行此操作的重要类是 StreamingContext
。
此类方便地具有名为 Context
的属性(可以在构造函数参数additional
中设置。
来自 MSDN :
additional
Type: System.Object
Any additional information to be associated with the StreamingContext. This information is available to any object that implements ISerializable or any serialization surrogate. Most users do not need to set this parameter.
所以这里有一些关于如何做到这一点的示例代码(在 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
这正是我想要的。
关于c# - 如何将自定义数据传递给反序列化函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7664198/