反序列化器不了解映射到此合约的任何类型
我正在尝试序列化和反序列化 Node 对象树。 我的抽象“Node”类以及从它派生的其他抽象和具体类在我的“Informa”项目中定义。 另外,我在 Informa 中创建了一个静态类用于序列化/反序列化。
首先,我将树解构为 Dictionary(guid,Node) 类型的平面列表,其中 guid 是 Node 的唯一 id。
我能够毫无问题地序列化所有节点。 但是当我尝试反序列化时,出现以下异常。
第 1 行位置 227 处出现错误。元素 'http://schemas.microsoft.com/2003/10/Serialization/Arrays :值' 包含的数据 “Informa:Building”数据合同。 这 解串器不知道任何 映射到此合约的类型。 添加 与“建筑物”对应的类型 到已知类型列表 - 对于 例如,通过使用 KnownTypeAttribute 或将其添加到 传递给的已知类型列表 DataContract 序列化器。
所有从 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;
}
}
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.
First I'm deconstructing my tree into a flat list of type Dictionary(guid,Node) where guid is the unique id of Node.
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.
All classes that derive from Node, including Building, have the [KnownType(typeof(type t))] attribute applied to them.
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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
KnownType
通常应用于base 类型 - 即(注意 - 您也可以在
DataContractSerializer
构造函数中指定已知类型,而不需要属性)编辑您的回复
如果框架类不知道所有派生类型,那么您需要在创建序列化器时指定已知类型:
这可以与(例如)
preserveObjectReferences
等,替换前面示例中的null
。END EDIT
但是,如果没有可重现的东西(即
Node
和Building
),就很难有太大帮助。另一个奇怪的事情是; 树结构非常适合诸如
DataContractSerializer
之类的东西 - 通常不需要先展平它们,因为树可以简单地用 xml 来表达。 你真的需要把它压平吗?例子:
KnownType
is usually applied to the base type - i.e.(note - you can also specify the known-types in the
DataContractSerializer
constructor, without requiring attributes)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:
This can be combined with (for example)
preserveObjectReferences
etc by replacing thenull
in the previous example.END EDIT
However, without something reproducible (i.e.
Node
andBuilding
), it is going to be hard to help much.The other odd thing; trees structures are very well suited to 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?Example:
好吧,这是一个图表,应该会让事情变得更清楚。 我正在为另一个程序开发一个插件,该插件添加了该程序中尚未包含的关系和属性。 这些关系/属性在我的树结构中定义。 然而,我试图抽象地定义这个结构,以便我可以为不同的程序创建插件的实现,以及从单个“查看器”程序中的多个实现访问信息。
我的序列化/反序列化方法是在框架中定义的,但框架不知道所有实现。 我希望我可以避免让实现项目将类型列表传递给框架项目中的保存/打开/序列化/反序列化方法,但似乎我无法避免这一点? 我想这是有道理的,序列化/反序列化方法必须能够访问它们正在反序列化的类型。
http://dl.getdropbox.com/u/113068/informa_framework.jpg <---大版本
替代文本 http://dl.getdropbox.com/u/113068/informa_framework.jpg< /a>
所以这并不能真正解释 Building 的问题,因为它是框架项目中的一个具体类。 我认为发生的事情是当我序列化 DataContractSerializer 可以访问所有对象及其 KnowType 参数并正确保存它们时。 但是当我反序列化时,我使用 Dictionary 作为类型创建 DataContractSerializer。 所以它只知道节点,而不知道节点的派生类。
我无法告诉它所有派生类型是什么,因为就像我说的那样,它们位于框架项目不知道的其他项目中。 Soooooooo 似乎最好的解决方案是让每个实现将其使用的 Node 类型列表传递给框架项目中的序列化和反序列化方法。
这有道理吗? 有一个更好的方法吗?
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.
http://dl.getdropbox.com/u/113068/informa_framework.jpg <---Larger Version
alt text 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.
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.
Does this make sense? Is there a better way to do this?
KnownTypes 属性的这两种用法有什么区别? 我没有意识到您可以/想要指定一个类是另一个类的 KnownType。
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.