用binaryformatter反序列化 [英] Deserialization with binaryformatter

查看:89
本文介绍了用binaryformatter反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a program that serializes an object and sends it over a network:

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);
}

另一方面,我收到并反序列化了这样的代码:

And on the other side I receive and deserialize the code as such:

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();
}

但是当我反序列化时,我遇到一个有关程序集丢失的错误:

But when I deserialized I got this error about an assembly missing:


在Server.exe中发生了类型为 System.Runtime.Serialization.SerializationException 的未处理异常其他信息:无法找到程序集'Client,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'。

"An unhandled exception of type System.Runtime.Serialization.SerializationException occurred in Server.exe Additional information: Unable to find assembly '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;
    }
}

但是现在我尝试这样做,我继续出现错误消息:

But now that I try to do it, I keep getting an error that says:


Server.Kort 类型的对象不能是转换为 Server.Kort +kortvalör类型。

"Object of type Server.Kort cannot be converted to type Server.Kort+kortvalör."

我不知道如何解决它。

推荐答案

发送方的类 Kort 必须包含嵌套类型的实例(也许是 enum ?)称为kortvalör。而且,由于 BinaryFormatter 会序列化public&私有的 fields 而不是属性,嵌套的类型可能对外界完全不可见,但是仍然可以序列化。

The class Kort on the sending side must contain an instance of a nested type (perhaps an enum?) called kortvalör. And, since BinaryFormatter serializes public & private fields instead of properties, the nested type could be completely invisible to the outside world, but still get serialized.

例如,我能够重现您的异常 Server类型的对象。Kort无法转换为Server.Kort +kortvalör类型 使用具有以下类的活页夹:

For instance, I was able to reproduce your exception "Object of type Server.Kort cannot be converted to type Server.Kort+kortvalör" using your binder with the following class:

[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 表示 Kort -然后一次用类型名 MyClientNamespace.Kort +kortvalör 。由于您的资料夹会忽略传入的 typeName 并返回 typeof(Kort),因此失败。

When deserializing the class above, your binder will be called twice, once with the typeName for Kort -- and then once with the typename "MyClientNamespace.Kort+kortvalör". Since your binder ignores the incoming typeName and returns typeof(Kort), this fails.

您可以选择一些方法来解决此问题:

You have a few options to solve this problem:


  1. 提取课程链接到共享的DLL,并将其与发送和接收应用程序链接。然后问题解决了。

  1. Extract your class Kort into a shared DLL and link it with both the sending and receiving applications. Then the problem goes away.

在发送方和发送方创建由 Kort 引用的所有类型的重复项接收应用程序-包括私有嵌套类型-并在 SerializationBinder 的智能版本中适当地重新映射类型名称。文章高级二进制序列化:将对象反序列化为不同类型的T 中有一个示例。

Create duplicates of all types referenced by Kort in both the sending and receiving applications -- including private nested types -- and remap the type names appropriately inside a smarter version of your SerializationBinder. The article Advanced Binary Serialization: Deserializing an Object Into a Different Type Than the One It was Serialized Into has an example of how to do it.

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

Consider using a different serialization format that serializes properties rather than private fields. BSON is one option. Protobuf-net is another.

这篇关于用binaryformatter反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆