2014-12-15 1 views
1

내 프로그램을 추상화하려고 시도하면서 f- 바운드 다형성을 사용하여 값을 정의합니다. 나는 DataContractJsonSerializer을 사용합니다 (선택의 여지가 없습니다). 유일한 문제는 제네릭의 경우 분명히 형식 이름이 잘못된 형식 (아래 끝에서 5 번째 줄)이라고 말하는 XmlException입니다.DataContractJsonSerializer가 범용/다형성 객체에서 실패합니다.

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을 던진다.

은 '{'문자, 16 진수 값 0x7B는 이름에 포함되지 않을 수 있습니다. "} System.Exception {System.Xml.XmlException}

내가이 찾을 변수를 디버깅 :

내가 그들을 없었 제네릭을 사용하기 전에? IsValidNCName. 나는이 예외를 극복 할 수있는 방법이라는 함수에서 테스트하지만, 난 다시 가고 싶지 않아
localName  "TreeOf{0}{#}"  string 

.

--edit--

내가 성공하지 않고, 그래서 올바른 유형을 소요 new DataContractJsonSerializer(typeof (ConcTree<StringValue>));을 사용했습니다.

답변

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

을 그리고 지금은 완벽하게 작동합니다!

관련 문제