我们公司的解决方案之一消耗第三方服务。通过XML消息传递完成通信。在我们的最后,我们基于它们提供给我们的XML模式生成要使用的类,并且在某些时候我们将这些类型中的一些序列化为数据库中的二进制blob以供以后使用。
问题出现在第三方公司将其中一个字段从布尔值更改为整数类型的位置。现在,当我们尝试对已经存在的数据进行反序列化时,我们可以预见到会发生类型转换异常(无法从布尔值转换为整数)。
我的问题是 - 我们如何使用旧的布尔类型对我们数据库中的现有数据进行反序列化以将其转换为新的整数类型?
我已经尝试了很多东西 - 其中包括反思和实现ISerializable,但到目前为止还没有任何东西被淘汰。理想的解决方案是实现ISerializable,但是在尝试反序列化现有数据时遇到“未找到成员”错误,因为它已经仅使用Serializable属性进行了序列化。
欢迎任何建议!
编辑:添加一些代码以清楚地展示我的问题。
namespace ClassLibrary
{
[Serializable]
public class Foo //: ISerializable
{
public bool Bar { get; set; }
public Foo() { }
//[OnDeserializing()]
//internal void OnDeserializingMethod(StreamingContext context)
//{
// Bar = 10;
//}
//public Foo(SerializationInfo info, StreamingContext context)
//{
// Bar = (int)info.GetValue("Bar", typeof(int));
//}
//public void GetObjectData(SerializationInfo info, StreamingContext context)
//{
// info.AddValue("Bar", Bar);
//}
}
}
namespace ConsoleApplication2
{
static class Program
{
static void Main(string[] args)
{
Foo foo;
// Run #1, where Foo.Bar is a boolean
foo = new Foo();
foo.Bar = true;
SerializeObject(foo);
byte[] data = File.ReadAllBytes(@".\Test.bin");
foo = DeserializeObject(data) as Foo;
// Now change Foo.Bar to an integer type, comment the lines above, and uncomment the two lines below
//byte[] newData = File.ReadAllBytes(@".\Test.bin");
//foo = DeserializeObject(newData) as Foo;
Console.WriteLine(foo.Bar);
Console.ReadLine();
}
private static Object DeserializeObject(byte[] buff)
{
if (buff == null) return null;
BinaryFormatter formatter = new BinaryFormatter();
formatter.Binder = new CustomSerializationBinder();
MemoryStream ms = new MemoryStream(buff);
return formatter.Deserialize(ms);
}
private static void SerializeObject(Object obj)
{
if (obj == null) return;
BinaryFormatter formatter = new BinaryFormatter();
using (FileStream ms = new FileStream(@".\Test.bin", FileMode.Create))
{
formatter.Serialize(ms, obj);
}
}
}
您可以使用ISerializable
处理这种情况,但是您需要使用SerializationInfo.GetEnumerator
遍历反序列化的属性,以确定实际从流中读取的数据类型。此外,您需要注意BinaryFormatter
序列化字段而不是属性,因此如果您的类使用Auto-Implemented Properties,则先前存储在二进制流中的名称将是name of the backing field而不是属性的名称。
例如,假设这是您原来的类:
[Serializable]
public class Foo
{
public bool Bar { get; set; }
public Foo() { }
}
现在您想将Bar
更改为整数。要序列化或反序列化旧的和新的BinaryFormatter
流,请使用以下ISerializable
实现:
[Serializable]
public class Foo : ISerializable
{
public int Bar { get; set; }
public Foo() { }
public Foo(SerializationInfo info, StreamingContext context)
{
var enumerator = info.GetEnumerator();
while (enumerator.MoveNext())
{
var current = enumerator.Current;
Debug.WriteLine(string.Format("{0} of type {1}: {2}", current.Name, current.ObjectType, current.Value));
if (current.Name == "Bar" && current.ObjectType == typeof(int))
{
Bar = (int)current.Value;
}
else if (current.Name == "<Bar>k__BackingField" && current.ObjectType == typeof(bool))
{
var old = (bool)current.Value;
Bar = (old ? 1 : 0); // Or whatever.
}
}
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Bar", Bar);
}
}
如果我们将布尔值转换为整数,那么它将是0或1.你能否尝试:
int val=int.Tryparse(myBooleanValue);
要么
int val= myBooleanValue?1:0;