DeSerialization дает странную ошибку во время выполнения? - PullRequest
0 голосов
/ 11 июля 2011

Десериализация не работает.Это дает мне следующую ошибку во время выполнения:

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 ]

2 голосов
/ 11 июля 2011

Редактировать:

Имена сборок консольных приложений различны, поэтому даже если имена пространств и типов совпадают, BinaryFormatter по-прежнему записывает имя сборки.Определите класс Measurement в общей сборке библиотеки классов и сделайте ссылку на него из обоих консольных приложений.

Исходный ответ:

Скорее всего, сторона, сериализующая объект, была скомпилирована с другой версиейСборка, чем сторона, которая его десериализовала.Проверьте в файле AssemblyInfo.cs сборку, содержащую измерение, чтобы убедиться, что AssemblyVersion полностью указан.

[assembly: AssemblyVersion("1.0.0.0")]

not

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

Если это не сработает, убедитесь, чтоэтот файл сборки идентичен в обоих местах.

0 голосов
/ 12 июля 2011

Еще одно решение, которое может вам помочь.Установите для свойства AssemblyFormat объекта BinaryFormatter значение Simple в методах сериализации и десериализации:

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

Помогает ли это?

0 голосов
/ 12 июля 2011

Поскольку (комментарии) вы выразили заинтересованность в том, чтобы избежать этого сценария, вот как я бы это сделал:

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 клиент)
  • не привязан к какому-либо конкретному типу или имени поля
  • нет риска случайной сериализации дополнительных объектов через подписку на события и т. Д.
  • полностью поддерживаются наиболее распространенные концепции сериализации
0 голосов
/ 11 июля 2011

Просто пытаюсь угадать: вы пытаетесь десериализовать двоичные файлы с классом Measurement, который теперь находится в другом пространстве имен, чем в момент сериализации этого файла.

Проверьте код, который ранее сериализовал ваши данныеи проверьте , что Measurement namepsace в отношении вашего.

С уважением.

0 голосов
/ 11 июля 2011

Вы получите эту ошибку, если у вас есть два приложения, одно сериализованное и одно десериализованное, и они совместно используют DLL с сериализованным типом (измерение), но общие библиотеки DLL - это разные сборки.

...