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 ответов
Редактировать:
Имена сборок консольных приложений различаются, поэтому даже если имена пространств и типов совпадают, BinaryFormatter по-прежнему записывает имя сборки. Определите класс Measurement в общей сборке библиотеки классов и сделайте ссылку на него из обоих консольных приложений.
Оригинальный ответ:
Скорее всего, сторона, которая сериализовала объект, была скомпилирована с другой версией сборки, чем сторона, которая его десериализовала. Проверьте в файле AssemblyInfo.cs сборку, содержащую измерение, чтобы убедиться, что AssemblyVersion полностью указан.
[assembly: AssemblyVersion("1.0.0.0")]
не
[assembly: AssemblyVersion("1.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)
- не привязан к какому-либо конкретному типу или имени поля
- нет риска случайной сериализации дополнительных объектов через подписку на события и т. д.
- наиболее распространенные концепции сериализации полностью поддерживаются
Вы получите эту ошибку, если у вас есть два приложения, одно сериализованное и одно десериализованное, и они совместно используют DLL с сериализованным типом (Измерение), но общие библиотеки DLL - это разные сборки.
Просто пытаюсь угадать: вы пытаетесь десериализовать двоичные файлы с Measurement
класс, который теперь находится в другом пространстве имен, чем в момент сериализации этого файла.
Проверьте код, который ранее сериализовал ваши данные и убедитесь, что Measurement
namepsace в отношении твоего.
С уважением.
Еще одно решение, которое может вам помочь. Установите для свойства Asse mblyFormat объекта BinaryFormatter значение Simple в методах сериализации и десериализации:
bf.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
Это помогает?