C# 反序列化器没有映射到此合约的任何类型的知识

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/736900/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:12:16  来源:igfitidea点击:

The deserializer has no knowlege of any type that maps to this contract

c#serializationdatacontractserializer

提问by Eric Anastas

I'm trying to serialize and deserialize a tree of Node objects. My abstract "Node" class as well as other abstract and concrete classes that derive from it are defined in my "Informa" project. In addition, I've created a static class in Informa for serialization / deserialization.

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

First I'm deconstructing my tree into a flat list of type Dictionary(guid,Node)where guid is the unique id of Node.

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

I am able to serialize all my Nodes with out a problem. But when I try to deserialize I get the following exception.

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

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.

第 1 行位置 227 中的错误。元素“ http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value”包含“Informa:Building”数据协定的数据。解串器没有映射到此合约的任何类型的知识。将与“Building”对应的类型添加到已知类型列表中 - 例如,通过使用 knownTypeAttribute 或将其添加到传递给 DataContract Serializer 的已知类型列表中。

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

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

My serialization and deserialization methods are below:

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

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

}

采纳答案by Marc Gravell

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

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

KnownTypeis usually applied to the basetype - i.e.

KnownType通常应用于基本类型 - 即

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

(note - you can also specify the known-types in the DataContractSerializerconstructor, without requiring attributes)

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

EDIT RE YOUR REPLY

编辑回复

If the framwork class doesn't know about all the derived types, then you need to specify the known types when creating the serializer:

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

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

This can be combined with (for example) preserveObjectReferencesetc by replacing the nullin the previous example.

这可以preserveObjectReferences通过替换null上一个示例中的与(例如)等组合。

END EDIT

结束编辑

However, without something reproducible (i.e. Nodeand Building), it is going to be hard to help much.

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

The other odd thing; trees structures are very well suitedto things like DataContractSerializer- there is usually no need to flatten them first, since trees can be trivially expressed in xml. Do you really need to flatten it?

另一件奇怪的事情;树结构非常适合这样的事情DataContractSerializer- 通常不需要先将它们展平,因为树可以用 xml 简单地表达。你真的需要把它弄平吗?



Example:

例子:

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

回答by Eric Anastas

What is the difference between these two uses of the KnownTypes attribute? I didn't realize that you could/would want to specify that one class is a KnownType of another.

已知类型属性的这两种用法之间有什么区别?我没有意识到您可以/想要指定一个类是另一个类的已知类型。

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


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

回答by Eric Anastas

Alright here's a diagram that should make things more clear. I'm developing a plugin for another program that adds relationships and properties not already included in the program. These relationships/properties are defined in my tree structure. However, I'm trying to define this structure abstractly so that I could create implementations of the plugin for different programs, as well as access the information from multiple implementations in a single "viewer" program.

好的,这是一张应该让事情更清楚的图表。我正在为另一个程序开发一个插件,该插件添加了程序中尚未包含的关系和属性。这些关系/属性在我的树结构中定义。但是,我试图抽象地定义这个结构,以便我可以为不同的程序创建插件的实现,以及在单个“查看器”程序中访问来自多个实现的信息。

My Serialize/Deserialize methods are defined in the framework, but the framework does not know about all the implementations. I was hoping I could avoid having the implementation projects pass a list of types to the save/open/serialize/deserialize methods in the framework project, but it seems I can't avoid this? I guess that make sense though, the serialize/deserialize methods must have access to the types they are deserializing.

我的 Serialize/Deserialize 方法是在框架中定义的,但是框架并不知道所有的实现。我希望我可以避免让实现项目将类型列表传递给框架项目中的保存/打开/序列化/反序列化方法,但似乎我无法避免这种情况?我想这是有道理的,序列化/反序列化方法必须能够访问它们正在反序列化的类型。

http://dl.getdropbox.com/u/113068/informa_framework.jpg<---Larger Version alt text http://dl.getdropbox.com/u/113068/informa_framework.jpg

http://dl.getdropbox.com/u/113068/informa_framework.jpg<---大版本 替代文字 http://dl.getdropbox.com/u/113068/informa_framework.jpg

So this doesn't really explain the problem with Building, as it is a concrete class in the framework project. I think what is happening is when I serialize the DataContractSerializer has access to all the objects and their KnowType parameter and saves them correctly. But when I deserialize I create my DataContractSerializer with Dictionary as the type. So it only knows about Nodes, but not the derived classes of nodes.

所以这并不能真正解释 Building 的问题,因为它是框架项目中的一个具体类。我认为发生的事情是当我序列化 DataContractSerializer 可以访问所有对象及其 KnowType 参数并正确保存它们时。但是当我反序列化时,我使用 Dictionary 作为类型创建了我的 DataContractSerializer。所以它只知道节点,而不知道节点的派生类。

new DataContractSerializer(typeof(Dictionary<Guid, Node>))

I can't tell it what all the derived types are because like I said they are in other projects that the framework project doesn't know about. Soooooooo seems like the best solution is to have each implementation pass a list of Node types it uses to the serialization and deserialization methods in the framework project.

我无法告诉它所有派生类型是什么,因为就像我说的那样,它们在框架项目不知道的其他项目中。Sooooooooo 似乎最好的解决方案是让每个实现将它使用的 Node 类型列表传递给框架项目中的序列化和反序列化方法。

Does this make sense? Is there a better way to do this?

这有意义吗?有一个更好的方法吗?