在C#中二进制反序列化期间更改类型

时间:2015-05-04 00:42:05

标签: c# serialization blob binaryformatter

我们公司的解决方案之一消耗第三方服务。通过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);
            }
        }
    }

2 个答案:

答案 0 :(得分:5)

您可以使用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);
    }
}

答案 1 :(得分:0)

如果我们将布尔值转换为整数,那么它将是0或1.你能否尝试:

int val=int.Tryparse(myBooleanValue);

int val= myBooleanValue?1:0;