我想serialize和deserialize一棵树的节点对象。我抽象的"节点"类以及其他的抽象和具体的课程,来自它的定义是在我的"信息"的项目。此外,我已经创建了一个静态的类信息序列化/反.

首先,我解构了我的树成平清单的类型 字典(guid,节点) 在guid的唯一标识的节点。

我能够serialize我所有的节点出一个问题。但是,当我试着deserialize我得到以下的例外。

误差在1号线的位置227.元素 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' 包含的数据 '信息:建立数据合同。的 解串没有知识的任何 类型的地图,这种合同。添加 的类型对应于'建筑' 清单已知类型的-对 例如,通过usying的 KnownTypeAttribute或通过增加它 该清单已知类型过来 DataContract序列化程序。

所有课程,从节点,其中包括建立有 [KnownType(类型(型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;
    }

}
有帮助吗?

解决方案

所有课程,从节点, 其中包括建立有 [KnownType(类型(型t))]属性 施加给他们。

KnownType 通常施加 基地 类型--即

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

其他提示

好吧这里有一个图,应该使事情更清楚了。我正在开发一个插件对于另一个程序,增加了关系和特性已经不包括在该程序。这些关系/性的定义是在我的树形结构。但是,我试图界定这一结构的抽象这样我就可以创建实现的插件对于不同的程序,以及访问的信息来自多个实现在一个单一的"观察者"的节目。

我Serialize/Deserialize方法中定义的框架,但框架不知道所有的实现。我希望我可以避免具有执行项目的通过的名单类型的节省/open/serialize/deserialize方法框架中的项目,但似乎我不能避免这种情况?我想有意义,虽然,serialize/deserialize方法必须能够访问的类型,他们反序列化.

http://dl.getdropbox.com/u/113068/informa_framework.jpg <---更大的版本 alt文本http://dl.getdropbox.com/u/113068/informa_framework.jpg

因此,这并没有真正解释的问题与建设,因为它是一个具体的类的框架的项目。我觉得发生了什么是当我serialize的DataContractSerializer有权访问所有的对象和他们的KnowType参数,节省他们正确。但是,当我deserialize创建我DataContractSerializer与词典作为类型。所以,它只知道有关节点,但不得出类的节点。

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

我不能告诉它什么的所有源类别,因为就像我说的他们是在其他项目的框架的项目不知道。特别特别在看来似乎最好的解决办法是让每个实施过列表的节点类型它使用的化和反的方法框架中的项目。

这有意义吗?有没有更好的方式做到这一点?

什么是这两者之间的区别使用的KnownTypes属性?我不知道,你可能会想要规定,一类是一个KnownType的另一个。

[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;}
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top