C# 抽象类的二进制反序列化实现

C# 抽象类的二进制反序列化实现,c#,serialization,C#,Serialization,我有一个抽象类,我正试图序列化和反序列化它的具体实现。在我的抽象基类中,我有: [DataContract] public class MyAbstractBase { [DataMember] public string Foo { get; set; } // some other abstract methods that derived classes have to implement } DataContractSerializer serializer

我有一个抽象类,我正试图序列化和反序列化它的具体实现。在我的抽象基类中,我有:

[DataContract]
public class MyAbstractBase
{
    [DataMember]
    public string Foo { get; set; }

    // some other abstract methods that derived classes have to implement
}
DataContractSerializer serializer = new DataContractSerializer(typeof(MyAbstractBase ), new List<Type>() { typeof(SomeOtherClass.MyDerivedClass) });
我向该类添加了一个要序列化的方法:

public string SerializeBase64()
{
    // Serialize to a base 64 string
    byte[] bytes;
    long length = 0;
    MemoryStream ws = new MemoryStream();
    DataContractSerializer serializer = new DataContractSerializer(this.GetType());
    XmlDictionaryWriter binaryDictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(ws);
    serializer.WriteObject(binaryDictionaryWriter, this);
    binaryDictionaryWriter.Flush();
    length = ws.Length;
    bytes = ws.GetBuffer();
    string encodedData = bytes.Length + ":" + Convert.ToBase64String(bytes, 0, bytes.Length, Base64FormattingOptions.None);
    return encodedData;
}
[DataContract]
[KnownType(typeof(SomeOtherclass.MyDerivedClass))]
public class MyAbstractBase
{
    [DataMember]
    public string Foo { get; set; }

    // some other abstract methods that derived classes have to implement
}
这似乎工作得很好,因为它会产生“某些东西”,并且实际上不会抛出任何错误

当然,问题在于反序列化。我补充说:

public static MyAbstractBase DeserializeBase64(string s)
{
    int p = s.IndexOf(':');
    int length = Convert.ToInt32(s.Substring(0, p));
    // Extract data from the base 64 string!
    byte[] memorydata = Convert.FromBase64String(s.Substring(p + 1));
    MemoryStream rs = new MemoryStream(memorydata, 0, length);
    DataContractSerializer serializer = new DataContractSerializer(typeof(MyAbstractBase ), new List<Type>() { typeof(SomeOtherClass.MyDerivedClass) });
    XmlDictionaryReader binaryDictionaryReader = XmlDictionaryReader.CreateBinaryReader(rs, XmlDictionaryReaderQuotas.Max);   
    return (MyAbstractBase)serializer.ReadObject(binaryDictionaryReader);
}
公共静态MyAbstractBase反序列化Base64(字符串s)
{
int p=s.IndexOf(':');
int length=Convert.ToInt32(s.Substring(0,p));
//从基64字符串中提取数据!
byte[]memorydata=Convert.FromBase64String(s.Substring(p+1));
MemoryStream rs=新的MemoryStream(MemoryStream,0,长度);
DataContractSerializer serializer=新的DataContractSerializer(typeof(MyAbstractBase),new List(){typeof(SomeOtherClass.MyDerivedClass)});
XmlDictionaryReader binaryDictionaryReader=XmlDictionaryReader.CreateBinaryReader(rs,XmlDictionaryReaderQuotas.Max);
return(MyAbstractBase)serializer.ReadObject(binaryDictionaryReader);
}
我认为通过将“已知类型”添加到我的
DataContractSerializer
,它将能够找出如何对派生类进行反序列化,但似乎没有。它抱怨错误:

应为命名空间“”中的元素“MyAbstractBase”。。遇到名称为“SomeOtherClass.MyDerivedClass”、命名空间为“”的“元素”

你知道我错过了什么吗

我在这里用一把网络提琴简单地演示了这个问题:


不幸的是,它不会直接在那里运行,因为它不包括
System.Runtime.Serialization
程序集。但是,如果将其放入Visual Studio项目中,它将很好地序列化,但会阻止反序列化。

序列化数据时,请使用与反序列化相同的重载序列化方法:

DataContractSerializer serializer = new DataContractSerializer(typeof(MyAbstractBase ), new List<Type>() { typeof(SomeOtherClass.MyDerivedClass) });

所以我发现了几个问题。首先是
CreateBinaryWriter
似乎根本不起作用。所以我放弃了它,直接用
serializer.WriteObject(ws,this)进行序列化

第二个问题是关于序列化,我这样做了:

DataContractSerializer serializer = new DataContractSerializer(this.GetType(), new List<Type>() { typeof(SomeOtherClass.MyDerivedClass) });

谢谢你的建议,但这似乎不是问题所在。在我的项目的其他地方,我设置了默认的序列化程序来覆盖派生类,所以这就是为什么我不需要它来进行序列化(也不应该需要它来进行反序列化,但我不确定它是否真的在接收它)。而
KnownType
属性只是为序列化程序提供类型列表的一种替代方法。我很确定您只需要一个或另一个(但我确实尝试了两个,只是为了确定我有相同的问题)。在上面的代码中,您不应该使用
ws.ToArray()
而不是
ws.GetBuffer()
Array.Copy()
?看见我认为这将消除问题,同时简化代码。
    public string SerializeBase64()
    {
        // Serialize to a base 64 string
        byte[] bytes;
        long length = 0;
        using (MemoryStream ws = new MemoryStream())
        {
            XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(ws);
            DataContractSerializer serializer = new DataContractSerializer(typeof(MyAbstractBase ), new List<Type>() { typeof(SomeOtherClass.MyDerivedClass) });
            serializer.WriteObject(writer, this);
            writer.Flush();
            length = ws.Length;
            // Note: https://msmvps.com/blogs/peterritchie/archive/2009/04/29/datacontractserializer-readobject-is-easily-confused.aspx
            // We need to trim nulls from the buffer produced by the serializer because it'll barf on them when it tries to deserialize.
            bytes = new byte[ws.Length];
            Array.Copy(ws.GetBuffer(), bytes, bytes.Length);
        }
        string encodedData = bytes.Length + ":" + Convert.ToBase64String(bytes, 0, bytes.Length, Base64FormattingOptions.None);
        return encodedData;
    }