DataContractJsonSerializer 在泛型/多态对象上失败



试图抽象我的程序,我使用f界多态来定义我的值。我使用DataContractJsonSerializer(别无选择)。唯一的问题是,显然对于泛型,它会抛出一个XmlException,说类型名称的格式不正确(下面末尾的第 5 行)。

public abstract class Value<T> where T : Value<T> {
}
public class StringValue : Value<StringValue> {
    [DataMember]
    public string S { get; set; }
}
[DataContract, KnownType("GetSubclasses")]
public abstract class Tree<TValue> where TValue : Value<TValue> {
    public static IEnumerable<Type> GetSubclasses() {
        return from t in typeof(Tree<>).Assembly.GetTypes()
               where typeof(Tree<>).IsAssignableFrom(t)
            select t;
    }
    [DataMember]
    public string Name;
    protected Tree() {}
}
[DataContract]
public class ConcTree<TValue> : Tree<TValue> where TValue : Value<TValue> { 
    [DataMember]
    public TValue Value;
    public ConcTree(string n, TValue reg) {
        Name = n;
        Value = reg;
    }
}
var result = new ConcTree<StringValue>("test", new StringValue() { S = "s_value" });
var serializer = new DataContractJsonSerializer(typeof (Tree<StringValue>));
using (var stream = new MemoryStream()) {
    serializer.WriteObject(stream, result); // Here XmlException
    stream.Position = 0;
    using (var reader = new StreamReader(stream))
        return reader.ReadToEnd();
}

它抛出一个XmlException或一个System.InvalidOperationException,取决于一些参数。

名称中不能包含"{"字符(十六进制值0x7B)。"} System.Exception {System.Xml.XmlException}

调试变量时,我发现:

    localName       "TreeOf{0}{#}"        string

在名为 IsValidNCName 的函数中进行测试。如何克服这些异常?在使用泛型之前,我从未拥有过它们,但我不想回去。

--编辑--

我试图使用new DataContractJsonSerializer(typeof (ConcTree<StringValue>));以便它采用正确的类型,但没有成功。

经过36小时的搜索,我终于找到了正确的方法。我不是在程序集中查找已注册的类型,而是向注册其类型的Tree的所有子类添加一个静态初始值设定项。

此外,如果我有一个高级类层次结构,我必须将通用参数TValue添加到已知类型列表中(参见 #1),尤其是对于反序列化。请参阅最后一部分。

[DataContract, KnownType("GetKnownSubclassesOfRegion")]
public abstract class Value<T> where T : Value<T> {
    //Register sub-types statically.
    protected static readonly List<Type> ValueTypes= new List<Type>();
    public static IEnumerable<Type> GetKnownSubclassesOfRegion() {
       return RegionTypes;
   }
}
[DataContract]
public class StringValue : Value<StringValue> {
    [DataMember]
    public string S { get; set; }
    static StringValue() {
        ValueTypes.Add(typeof(StringValue ));
    }
}

树也是如此:

[DataContract, KnownType("GetSubclasses")]
public abstract class Tree<TValue> where TValue : Value<TValue> {
    //Register sub-types statically with their generic parameter which is instantiated.
    protected static readonly List<Type> RegisteredTypes = new List<Type>();
    public static IEnumerable<Type> GetSubclasses() {      //This is new
        return RegisteredTypes;
    }
    static TreeElement() { // #1
        RegisteredTypes.Add(typeof(TValue));
    }
    [DataMember]
    public string Name;
    protected Tree() {}
}
[DataContract]
public class ConcTree<TValue> : Tree<TValue> where TValue : Value<TValue> { 
    [DataMember]
    public TValue Value;
    public ConcTree(string n, TValue reg) {
        Name = n;
        Value = reg;
    }
    static ConcTree() {  //This is new
        ValueTypes.Add(typeof(ConcTree<TValue>)); 
    }
}
var result = new ConcTree<StringValue>("test", new StringValue() { S = "s_value" });
var serializer = new DataContractJsonSerializer(typeof (Tree<StringValue>));
using (var stream = new MemoryStream()) {
    serializer.WriteObject(stream, result); // No exception anymore.
    stream.Position = 0;
    using (var reader = new StreamReader(stream))
        return reader.ReadToEnd();
}

现在它工作得很好!

最新更新