尝试抽象我的程序,我使用f-bounded多态来定义我的值。我使用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>));
以便它采用正确的类型,但没有成功。
答案 0 :(得分:1)
经过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();
}
现在它完美无缺!