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

一世执手 提交于 2019-11-29 15:19:20

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

KnownType is usually applied to the base type - i.e.

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

(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:

[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) preserveObjectReferences etc by replacing the null in the previous example.

END EDIT

However, without something reproducible (i.e. Node and Building), 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:

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

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.

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.

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

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;}
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!