DeSerialization给出了奇怪的运行时错误?

时间:2011-07-11 19:38:00

标签: c# serialization deserialization binary-deserialization

反序列化无效。它给了我以下运行时错误:

Unhandled Exception: System.InvalidCastException: Unable to cast object of 'Measurement' to type 'Measurement'.

我真的看不出它有什么问题。

//start alternate serialization
public static class AltSerialization
{
    public static byte[] AltSerialize(Measurement m)
    {
     using (var ms = new MemoryStream())
        {
            var bf = new BinaryFormatter();
            bf.Serialize(ms, m);
            return ms.GetBuffer();
        }
    }

    public static Measurement AltDeSerialize(byte[] seriM)    
    {
    using (var stream = new MemoryStream( seriM ))
        {
            BinaryFormatter bf = new BinaryFormatter();
            return (Measurement)bf.Deserialize(stream);         
        }
    } 
}
//end alternte serialization

[Serializable] //This attribute sets class to be serialized
public class Measurement : ISerializable
{            
    [NonSerialized] public int id;
    public int time; //timestamp
    public double value;

    public Measurement()
    {
        id = 1;
        time = 12;
        value = 0.01;
    }

    public Measurement(int _id, int _time, double _value)
    {
        id = _id;
        time = _time;
        value = _value;
    }

    //Deserialization constructor   
    public Measurement(SerializationInfo info, StreamingContext ctxt)
    {
        //Assign the values from info to the approporiate properties    
        Console.WriteLine("DeSerialization construtor called.");
        time = (int)info.GetValue("MeasurementTime", typeof(int));
        value = (double)info.GetValue("MeasurementValue", typeof(double));
    }

    //Serialization function    
    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
    {
        // Custom name-value pair
        // Values must be read with the same name they're written       
        info.AddValue("MeasurementTime", time);
        info.AddValue("MeasurementValue", value);
    }
}


//AFTER THIS, IS FOR TEST FILES app1.cs, app2.cs, and the reference refer.cs.

//app1.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using refer;
using System.Reflection;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
[assembly: AssemblyVersion("1.0.0.0")]



public class MainClass
{
    public static void Main()
    {
        //Create a new Measurement message
        Measurement m1 = new Measurement(2, 2345, 23.456);
        System.Console.WriteLine("\nm1.id = {0}", m1.id);
        System.Console.WriteLine("m1.time = {0}", m1.time);
        System.Console.WriteLine("m1.value = {0}", m1.value);

        /*byte[] bArray = AltSerialization.AltSerialize( m1 );
        Measurement m2 = new Measurement();
        m2 = AltSerialization.AltDeSerialize(bArray);
        System.Console.WriteLine("\nm2.id = {0}", m2.id);
        System.Console.WriteLine("m2.time = {0}", m2.time);
        System.Console.WriteLine("m2.value = {0}", m2.value);*/

        ConnectionFactory factory = new ConnectionFactory();
        factory.HostName = "localhost";
        using (IConnection connection = factory.CreateConnection())
        using (IModel channel = connection.CreateModel())
        {
            channel.QueueDeclare("hello", true, false, false, null);

            byte[] body = refer.AltSerialization.AltSerialize( m1 );

            channel.BasicPublish("", "hello", null, body);
            Console.WriteLine(" [x] Sent ");
        }
    }
}


//app2.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using refer;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Reflection;
[assembly: AssemblyVersion("1.0.0.0")]



public class MainClass
{
    public static void Main()
    {

        /*/Create a new Measurement message
        Measurement m1 = new Measurement(2, 2345, 23.456);
        System.Console.WriteLine("\nm1.id = {0}", m1.id);
        System.Console.WriteLine("m1.time = {0}", m1.time);
        System.Console.WriteLine("m1.value = {0}", m1.value);

        byte[] bArray = AltSerialization.AltSerialize( m1 );*/

        Measurement m2 = new Measurement();

        ConnectionFactory factory = new ConnectionFactory();
        factory.HostName = "localhost";
        using (IConnection connection = factory.CreateConnection())
        using (IModel channel = connection.CreateModel()) {
            channel.QueueDeclare("hello", false, false, false, null);

            QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
            channel.BasicConsume("hello", true, consumer);

            System.Console.WriteLine(" [*] Waiting for messages." +
                                     "To exit press CTRL+C");

                BasicDeliverEventArgs ea =
                    (BasicDeliverEventArgs)consumer.Queue.Dequeue();

                m2 = refer.AltSerialization.AltDeSerialize(ea.Body); 

                System.Console.WriteLine(" \n[x] Received ");
                System.Console.WriteLine("\nm2.id = {0}", m2.id);
                System.Console.WriteLine("m2.time = {0}", m2.time);
                System.Console.WriteLine("m2.value = {0}", m2.value);
        }
    }
}

//refer.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

using System.Reflection;
[assembly: AssemblyVersion("1.0.0.0")]

namespace refer
{
    //start alternate serialization
    public static class AltSerialization
    {
        public static byte[] AltSerialize(Measurement m)
        {
         using (var ms = new MemoryStream())
            {
                var bf = new BinaryFormatter();
                bf.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
                bf.Serialize(ms, m);
                return ms.GetBuffer();
            }
        }

        public static Measurement AltDeSerialize(byte[] seriM)    
        {
        using (var stream = new MemoryStream( seriM ))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
                return (Measurement)bf.Deserialize(stream);         
            }
        } 
    }
    //end alternte serialization

    [Serializable] //This attribute sets class to be serialized
    public class Measurement : ISerializable
    {            
        [NonSerialized] public int id;
        public int time; //timestamp
        public double value;

        public Measurement()
        {
            id = 1;
            time = 12;
            value = 0.01;
        }

        public Measurement(int _id, int _time, double _value)
        {
            id = _id;
            time = _time;
            value = _value;
        }

        //Deserialization constructor   
        public Measurement(SerializationInfo info, StreamingContext ctxt)
        {
            //Assign the values from info to the approporiate properties    
            Console.WriteLine("DeSerialization construtor called.");
            time = (int)info.GetValue("MeasurementTime", typeof(int));
            value = (double)info.GetValue("MeasurementValue", typeof(double));
        }

        //Serialization function    
        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            // Custom name-value pair
            // Values must be read with the same name they're written       
            info.AddValue("MeasurementTime", time);
            info.AddValue("MeasurementValue", value);
        }
    }
}
public class MainClass
{
    public static void Main() 
    {

    }
}

5 个答案:

答案 0 :(得分:2)

编辑:

控制台应用程序的程序集名称不同,因此即使命名空间和类型名称相同,BinaryFormatter仍会记录程序集的名称。在公共类库程序集中定义Measurement类,并从两个控制台应用程序引用它。

原始答案:

最有可能的是,序列化对象的那一方是使用不同版本的程序集编译的,而不是反序列化它的那一方。在AssemblyInfo.cs文件中检查包含Measurement的程序集,以确保完全指定AssemblyVersion。

[assembly: AssemblyVersion("1.0.0.0")]

[assembly: AssemblyVersion("1.0.*")]

如果这不起作用,请确保两个地方的程序集文件相同。

答案 1 :(得分:0)

如果您有两个应用程序,一个序列化和一个反序列化,并且它们与序列化类型(Measurment)共享DLL,但共享DLL是不同的构建版本,则会出现此错误。

答案 2 :(得分:0)

只是想猜测:你正在尝试使用Measurement类反序列化二进制文件,该类现在位于不同的命名空间中,然后在该文件的序列化时刻。

检查先前已对您的数据进行序列化的代码,并检查 Measurement名称与您的关系。

问候。

答案 3 :(得分:0)

由于(评论)你表示有兴趣避免这种情况,所以我会这样做:

using System.IO;
using ProtoBuf;
public static class AltSerialization
{
    public static byte[] AltSerialize(Measurement m)
    {
        using (var ms = new MemoryStream())
        {
            Serializer.Serialize(ms, m);
            return ms.ToArray();
        }
    }

    public static Measurement AltDeSerialize(byte[] seriM)
    {
        using (var stream = new MemoryStream(seriM))
        {
            return Serializer.Deserialize<Measurement>(stream);
        }
    }
}

[ProtoContract]
public class Measurement
{
    public int id; // not serialized
    [ProtoMember(1)]
    public int time; // serialized as field 1
    [ProtoMember(2)]
    public double value; // serialized as field 2

    public Measurement()
    {
        id = 1;
        time = 12;
        value = 0.01;
    }

    public Measurement(int _id, int _time, double _value)
    {
        id = _id;
        time = _time;
        value = _value;
    }
}

好吧,除了我没有公共字段; p如果你不想要这些属性,也可以通过多种方式避免它们,如果你真的想要我可以解释。

优点:

  • 越来越快
  • 没有绑定任何平台(你可以很容易地在C ++ / java / etc protobuf客户端加载它)
  • 不依赖于任何特定类型或字段名称
  • 没有通过事件订阅等意外序列化额外对象的风险
  • 完全支持最常见的序列化概念

答案 4 :(得分:0)

还有一个解决方案可能对您有所帮助。在序列化和反序列化方法中将BinaryFormatter的AssemblyFormat属性设置为Simple值:

bf.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;

这有帮助吗?