c# - 反序列化器不知道映射到该契约的任何类型

标签 c# serialization datacontractserializer

我正在尝试序列化和反序列化 Node 对象树。我的抽象“节点”类以及从它派生的其他抽象类和具体类都在我的“Informa”项目中定义。此外,我在 Informa 中创建了一个用于序列化/反序列化的静态类。

首先,我将我的树解构为 Dictionary(guid,Node) 类型的平面列表,其中 guid 是节点的唯一 ID。

我能够毫无问题地序列化我的所有节点。但是当我尝试反序列化时,出现以下异常。

Error in line 1 position 227. Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' contains data of the 'Informa:Building' data contract. The deserializer has no knowlege of any type that maps to this contract. Add the type corresponding to 'Building' to the list of known types - for example, by usying the KnownTypeAttribute or by adding it to the list of known types passed to DataContract Serializer.

所有派生自 Node 的类,包括 Building,都应用了 [KnownType(typeof(type t))] 属性。

我的序列化和反序列化方法如下:

public static void SerializeProject(Project project, string filePath)
{
    try
    {
        Dictionary<Guid, Node> nodeDic = DeconstructProject(project);

        Stream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None);

        //serialize

        DataContractSerializer ser = new DataContractSerializer(typeof(Dictionary<Guid, Node>),"InformaProject","Informa");

        ser.WriteObject(stream,nodeDic);

        // Cleanup
        stream.Close();
    }
    catch (Exception e)
    {
        MessageBox.Show("There was a problem serializing " + Path.GetFileName(filePath) + ". \n\nException:" + e.Message, "Doh!", MessageBoxButtons.OK, MessageBoxIcon.Error);
        throw e;
    }

}



public static Project DeSerializeProject(string filePath)
{
    try
    {
        Project proj;

        // Read the file back into a stream
        Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);

        DataContractSerializer ser = new DataContractSerializer(typeof(Dictionary<Guid, Node>), "InformaProject", "Informa");

        Dictionary<Guid, Node> nodeDic = (Dictionary<Guid, Node>)ser.ReadObject(stream);

        proj = ReconstructProject(nodeDic);        

        // Cleanup
        stream.Close();

        return proj;

    }
    catch (Exception e)
    {
        MessageBox.Show("There was a problem deserializing " + Path.GetFileName(filePath) + ". \n\nException:" + e.Message, "Doh!", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
    }

}

最佳答案

All classes that derive from Node, including Building, have the [KnownType(typeof(type t))] attribute applied to them.

KnownType 通常应用于 base 类型 - 即

[DataContract, KnownType(typeof(Building)), ...]
abstract class Node { ... }

(注意 - 您还可以在 DataContractSerializer 构造函数中指定已知类型,不需要属性)

编辑您的回复

如果框架类不知道所有派生类型,那么您需要在创建序列化程序时指定已知类型:

[DataContract] abstract class SomeBase { }
[DataContract] class Foo : SomeBase { }
[DataContract] class Bar : SomeBase { }
...
// here the knownTypes argument is important
new DataContractSerializer(typeof(SomeBase),
      new Type[] { typeof(Foo), typeof(Bar) });

这可以与(例如)preserveObjectReferences 等结合使用,方法是替换上一个示例中的 null

结束编辑

但是,如果没有可重现的东西(即 NodeBuilding),将很难提供太多帮助。

另一个奇怪的事情;树结构非常适合DataContractSerializer之类的东西——通常不需要先将它们展平,因为树可以简单地用 xml 表示。你真的需要把它弄平吗?


例子:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;

[DataContract, KnownType(typeof(Building))]
abstract class Node {
    [DataMember]
    public int Foo {get;set;}
}
[DataContract]
class Building : Node {
    [DataMember]
    public string Bar {get;set;}
}

static class Program
{
    static void Main()
    {
        Dictionary<Guid, Node> data = new Dictionary<Guid, Node>();
        Type type = typeof(Dictionary<Guid, Node>);
        data.Add(Guid.NewGuid(), new Building { Foo = 1, Bar = "a" });
        StringWriter sw = new StringWriter();
        using (XmlWriter xw = XmlWriter.Create(sw))
        {
            DataContractSerializer dcs = new DataContractSerializer(type);
            dcs.WriteObject(xw, data);
        }

        string xml = sw.ToString();

        StringReader sr = new StringReader(xml);
        using (XmlReader xr = XmlReader.Create(sr))
        {
            DataContractSerializer dcs = new DataContractSerializer(type);
            Dictionary<Guid, Node> clone = (Dictionary<Guid, Node>)
                dcs.ReadObject(xr);
            foreach (KeyValuePair<Guid, Node> pair in clone)
            {
                Console.WriteLine(pair.Key + ": " + pair.Value.Foo + "/" +
                    ((Building)pair.Value).Bar);
            }
        }
    }
}

关于c# - 反序列化器不知道映射到该契约的任何类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/736900/

相关文章:

c# - 通过 C# 使用间接 url 下载

c# - WPF 中的 SQL Server 连接

objective-c - 数据序列化

c# - WCF 在没有 "set "的属性上阻塞。任何解决方法?

C# - 如何解析文本文件(空格分隔的数字)?

c# - 使用 IQueryable 创建动态查询

C# "Enum"序列化 - 反序列化为静态实例

java - json反序列化遇到一些问题

c# - DataContractSerializer 未正确反序列化,缺少对象中方法的值

c# - 在基元列表上使用 DataContractSerializer 的自定义元素名称