使用BinaryFormatter反序列化接口 [英] Deserializing Interfaces using BinaryFormatter

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

问题描述

我不认为我原来的帖子措辞得很好,所以这是我更准确地表达我的问题。  我遇到了一个问题,当我尝试使用BinaryFormatter(C#,.NET Framework 4.0)将曾经的具体类反序列化为接口
时,我会抛出异常。


 


为了概述类结构,我从一个引用另一个(ClassB)作为具体实例的类(ClassA)开始:

 [Serializable] 
公共类ClassA:ISerializable
{
public ClassB MyItem {get;组; }

public ClassA()
{
MyItem = null;
}

public ClassA(SerializationInfo info,StreamingContext context)
{
MyItem = SerializationHelper.GetValue(info," MyItem",(ClassB)null);
}

[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter = true)]
public virtual void GetObjectData(SerializationInfo info,StreamingContext context)
{
info .AddValue(" MyItem",MyItem);
}
}

[可序列化]
公共类ClassB:ISerializable
{
公共字符串值{get;组; }

public ClassB()
{
Value =" default" ;;
}

public ClassB(SerializationInfo info,StreamingContext context)
{
try
{
Value = info.GetString(" Value" );
}
catch(exception ex)
{
Value =" default" ;;
}
}

[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter = true)]
public virtual void GetObjectData(SerializationInfo info,StreamingContext context)
{
info.AddValue(" Value",Value);
}
}

 


但是,现在ClassB实现了一个接口(IBInterface), ClassA中的属性已更改为引用接口而不是具体类。

 [Serializable] 
公共类ClassA:ISerializable
{
public IBInterface MyItem {get;组; }

public ClassA()
{
MyItem = null;
}

public ClassA(SerializationInfo info,StreamingContext context)
{
MyItem = SerializationHelper.GetValue(info," MyItem",(IBInterface)null);
}

[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter = true)]
public virtual void GetObjectData(SerializationInfo info,StreamingContext context)
{
info .AddValue(" MyItem",MyItem);
}
}

[可序列化]
公共类ClassB:IBInterface,ISerializable
{
public string Value {get;组; }

public ClassB()
{
Value =" default" ;;
}

public ClassB(SerializationInfo info,StreamingContext context)
{
try
{
Value = info.GetString(" Value" );
}
catch(exception ex)
{
Value =" default" ;;
}
}

[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter = true)]
public virtual void GetObjectData(SerializationInfo info,StreamingContext context)
{
info.AddValue(" Value",Value);
}
}

公共接口IBInterface
{
string Value {get; }
}

 


我还创建了一个实现SerializationBinder的类,以便接口适当地反序列化。 / p>

公共类TypeConverter:SerializationBinder 
{
private const string ASSEMBLY =" SerializationTesting,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = NULL英寸;
private const string OLD_TYPE =" SerializationTesting.ClassB" ;;
private const string NEW_TYPE =" SerializationTesting.IBInterface" ;;

公共覆盖类型BindToType(字符串assemblyName,字符串typeName)
{
if(typeName.Contains(OLD_TYPE))
{
ReplaceType

ref typeName,
ref assemblyName,
OLD_TYPE,
ASSEMBLY,
NEW_TYPE,
ASSEMBLY
);
}

返回Type.GetType(string.Format(" {0},{1}",typeName,assemblyName));
}

private static void ReplaceType

ref string type,
ref string assembly,
string oldType,
string oldAssembly,
string newType,
string newAssembly

{
if(type == oldType)
{
type = newType;
assembly = newAssembly;
返回;
}

string oldTypeFull = string.Format(" {0},{1}",oldType,oldAssembly);

if(type.Contains(oldTypeFull))
{
string newTypeFull = string.Format(" {0},{1}" newType,newAssembly);
type = type.Replace(oldTypeFull,newTypeFull);
}
}
}

 


要反序列化数据,我打电话给方法类似于以下内容:

 public static IBInterface反序列化

byte []缓冲区,
IBInterface defaultValue

{
try
{
object deserializedObject;
BinaryFormatter binaryFormatter = new BinaryFormatter();

binaryFormatter.Binder = new TypeConverter();

using(MemoryStream stream = new MemoryStream(buffer))
{
stream.Seek(0,0);
deserializedObject = binaryFormatter.Deserialize(stream);
}

if(!(deserializedObject is IBInterface))
{
return defaultValue;
}

return(IBInterface)deserializedObject;
}
catch(Exception ex)
{
return defaultValue;
}
}

 


所以问题在于调用binaryFormatter.Deserialize(stream ),抛出一个SerializationException,在Assembly'SerializationTesting,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'中标记"Type"SerializationTesting.IBInterface',不将
标记为可序列化。"


 


我测试了使用get go(带接口)的第二个设置完成序列化时会发生什么,并且完全序列化和反序列化所以我知道反序列化可以通过接口完成,只要它们被序列化为接口即可。
 但是,在我的情况下,它首先没有被序列化为接口。  是否有我遗漏的东西,或者有这样的场景的解决方法?  我已经搜索了一段时间但还没有遇到任何问题。


 

解决方案

< blockquote>我在错误的部分发布了这个吗?  这是双重帖吗?  我做错了什么,因为我得到了几个零食但没有字节(对不起......糟糕的笑话)?


I don't think my original post was worded very well, so here's my go at a expressing my problem more precisely.  I have run across an issue where I am getting a exception thrown when trying to deserialize what was once a concrete class into an interface using a BinaryFormatter (C#, .NET Framework 4.0).

 

To give an overview of the class structure, I started off with a class (ClassA) that referenced another (ClassB) as a concrete instance:

[Serializable]
public class ClassA : ISerializable
{
    public ClassB MyItem { get; set; }

    public ClassA()
    {
        MyItem = null;
    }

    public ClassA(SerializationInfo info, StreamingContext context)
    {
        MyItem = SerializationHelper.GetValue(info, "MyItem", (ClassB)null);
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("MyItem", MyItem);
    }
}

[Serializable]
public class ClassB : ISerializable
{
    public string Value { get; set; }

    public ClassB()
    {
        Value = "default";
    }

    public ClassB(SerializationInfo info, StreamingContext context)
    {
        try
        {
            Value = info.GetString("Value");
        }
        catch (Exception ex)
        {
            Value = "default";
        }
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Value", Value);
    }
}

 

However, now ClassB implements an interface (IBInterface), and the property in ClassA has changed to refer to the interface rather than the concrete class.

[Serializable]
public class ClassA : ISerializable
{
    public IBInterface MyItem { get; set; }

    public ClassA()
    {
        MyItem = null;
    }

    public ClassA(SerializationInfo info, StreamingContext context)
    {
        MyItem = SerializationHelper.GetValue(info, "MyItem", (IBInterface)null);
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("MyItem", MyItem);
    }
}

[Serializable]
public class ClassB : IBInterface, ISerializable
{
    public string Value { get; set; }

    public ClassB()
    {
        Value = "default";
    }

    public ClassB(SerializationInfo info, StreamingContext context)
    {
        try
        {
            Value = info.GetString("Value");
        }
        catch (Exception ex)
        {
            Value = "default";
        }
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Value", Value);
    }
}

public interface IBInterface
{
    string Value { get; }
}

 

I also created a class that implements SerializationBinder so that the interface would deserialize appropriately.

public class TypeConverter : SerializationBinder
{
    private const string ASSEMBLY = "SerializationTesting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
    private const string OLD_TYPE = "SerializationTesting.ClassB";
    private const string NEW_TYPE = "SerializationTesting.IBInterface";

    public override Type BindToType(string assemblyName, string typeName)
    {
        if (typeName.Contains(OLD_TYPE))
        {
            ReplaceType
            (
                ref typeName,
                ref assemblyName,
                OLD_TYPE,
                ASSEMBLY,
                NEW_TYPE,
                ASSEMBLY
            );
        }

        return Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
    }

    private static void ReplaceType
    (
        ref string type,
        ref string assembly,
        string oldType,
        string oldAssembly,
        string newType,
        string newAssembly
    )
    {
        if (type == oldType)
        {
            type = newType;
            assembly = newAssembly;
            return;
        }

        string oldTypeFull = string.Format("{0}, {1}", oldType, oldAssembly);

        if (type.Contains(oldTypeFull))
        {
            string newTypeFull = string.Format("{0}, {1}", newType, newAssembly);
            type = type.Replace(oldTypeFull, newTypeFull);
        }
    }
}

 

To deserialize the data, I call a method similar to the following:

public static IBInterface Deserialize
(
    byte[] buffer,
    IBInterface defaultValue
)
{
    try
    {
        object deserializedObject;
        BinaryFormatter binaryFormatter = new BinaryFormatter();

        binaryFormatter.Binder = new TypeConverter();

        using (MemoryStream stream = new MemoryStream(buffer))
        {
            stream.Seek(0, 0);
            deserializedObject = binaryFormatter.Deserialize(stream);
        }

        if (!(deserializedObject is IBInterface))
        {
            return defaultValue;
        }

        return (IBInterface)deserializedObject;
    }
    catch (Exception ex)
    {
        return defaultValue;
    }
}

 

So the problem is that on the call binaryFormatter.Deserialize(stream), a SerializationException is thrown stating "Type 'SerializationTesting.IBInterface' in Assembly 'SerializationTesting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable."

 

I tested what happens when serialization is done using the second setup from the get go (with the interface), and that serialized and deserialized perfectly so I know deserialization can be done with interfaces so long as they were serialized as an interface.  However, in my case, it was not serialized as an interface first.  Is there something that I am missing, or is there a workaround for a scenario like this?  I've searched for a while now and have yet to come across anything.

 

解决方案

Did I post this in the wrong section?  Is this a double post?  What did I do wrong, 'cause I'm getting a few nibbles but no bytes (sorry... bad joke)?


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

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