【问题标题】:Deserialization with binaryformatter使用 binaryformatter 反序列化
【发布时间】:2015-05-12 16:23:25
【问题描述】:

我有一个程序可以序列化一个对象并通过网络发送它:

TcpClient client = new TcpClient();
client.ReceiveTimeout = 10000;
client.SendTimeout = 10000;
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
client.Connect(serverEndPoint);

BinaryFormatter binaryformatter = new BinaryFormatter();

NetworkStream networkStream = client.GetStream();
if (networkStream.CanWrite)
{
    binaryformatter.Serialize(networkStream, kort);
}

另一方面,我接收并反序列化代码:

TcpClient tcpClient = (TcpClient)client;
tcpClient.SendTimeout = 10000;
tcpClient.ReceiveTimeout = 10000;
NetworkStream clientStream = tcpClient.GetStream();
try
{
    if (clientStream.CanRead)
    {
        BinaryFormatter binaryformatter = new BinaryFormatter();
        binaryformatter.Binder = new AllowAllAssemblyVersionsDeserializationBinder();

        Kort tempkort = (Kort)binaryformatter.Deserialize(clientStream);
        SetImage(tempkort);
    }
}
catch (SerializationException e)
{
    MessageBox.Show("Failed to deserialize. Reason: " + e.Message);
    throw;
}
finally
{
    clientStream.Close();
    tcpClient.Close();
}

但是当我反序列化时,我收到了关于缺少程序集的错误:

“Server.exe 中出现 System.Runtime.Serialization.SerializationException 类型的未处理异常附加信息:无法找到程序集 'Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'。

我用这个解决了:

sealed class AllowAllAssemblyVersionsDeserializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {     
        String currentAssembly = Assembly.GetExecutingAssembly().FullName;

        // In this case we are always using the current assembly
        typeName = "Server.Kort";
        assemblyName = currentAssembly;

        // Get the type using the typeName and assemblyName
        Type typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
            typeName, assemblyName));

        return typeToDeserialize;
    }
}

但现在我尝试这样做,我不断收到一条错误消息:

Server.Kort 类型的对象无法转换为 Server.Kort+kortvalör 类型。”

我不知道如何解决它。

【问题讨论】:

  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • “但是当我反序列化时,我收到一个关于缺少程序集或其他东西的错误”发布该错误。
  • 我得到的错误是“Server.exe 中发生了“System.Runtime.Serialization.SerializationException”类型的未处理异常附加信息:找不到程序集“客户端,版本=1.0.0.0,文化=中性,PublicKeyToken=null'。”

标签: c# serialization .net-assembly binaryformatter


【解决方案1】:

发送端的类Kort 必须包含一个名为kortvalör 的嵌套类型(可能是enum?)的实例。而且,由于 BinaryFormatter 序列化公共和私有 字段 而不是属性,嵌套类型可能对外界完全不可见,但仍会被序列化。

例如,我能够使用带有以下类的活页夹重现您的异常"Object of type Server.Kort cannot be converted to type Server.Kort+kortvalör"

[Serializable]
public class Kort
{
    // Private enum that is invisible to the outside world.
    enum kortvalör 
    {
        Zero,
        One,
        Two,
        Three
    }

    kortvalör valör = kortvalör.Three;

    public int Value
    {
        get
        {
            return (int)valör;
        }
        set
        {
            // Check to make sure the incoming value is in a valid range.
            var newvalör = (kortvalör)value;
            if (Enum.IsDefined(typeof(kortvalör), newvalör))
                valör = newvalör;
            else
                valör = default(kortvalör);
        }
    }
}

当反序列化上面的类时,你的活页夹将被调用两次,一次是使用typeName for Kort -- 然后一次是使用类型名"MyClientNamespace.Kort+kortvalör"。由于您的活页夹忽略传入的typeName 并返回typeof(Kort),因此失败。

你有几个选项来解决这个问题:

  1. 将您的类 Kort 提取到共享 DLL 中,并将其与发送和接收应用程序链接。然后问题就消失了。

  2. 在发送和接收应用程序中创建Kort 引用的所有类型的副本(包括私有嵌套类型),并在SerializationBinder 的更智能版本中适当地重新映射类型名称。文章Advanced Binary Serialization: Deserializing an Object Into a Different Type Than the One It was Serialized Into 有一个如何做的例子。

  3. 考虑使用不同的序列化格式来序列化 properties 而不是私有字段。 BSON 是一种选择。 Protobuf-net 是另一个。

【讨论】:

  • 非常感谢,我做了第一步,效果很好。
猜你喜欢
  • 1970-01-01
  • 2014-12-10
  • 1970-01-01
  • 2013-09-23
  • 1970-01-01
  • 2012-08-12
  • 2011-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多