2009-07-24 15 views
9

Mam struct w C#, który otacza GUID. Używam DataContractJsonSerializer do serializacji obiektu zawierającego wystąpienie tej klasy. Kiedy używałam guid bezpośrednio, był serializowany jako zwykły ciąg znaków, ale teraz jest serializowany jako para nazwa/wartość. Oto test NUnit i kod wspieranie który demonstruje problem:Jak mogę spowodować, aby DataContractJsonSerializer serializuje obiekt jako ciąg znaków?

private static string ToJson<T>(T data) 
    { 
     DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof (T)); 

     using (MemoryStream ms = new MemoryStream()) 
     { 
      serializer.WriteObject(ms, data); 
      return Encoding.Default.GetString(ms.ToArray()); 
     } 
    } 

    [Serializable] 
    private class ID 
    { 
     private Guid _value; 

     public static explicit operator ID(Guid id) 
     { 
      return new ID { _value = id }; 
     } 

     public static explicit operator Guid(ID id) 
     { 
      return id._value; 
     } 
    } 

    [Test] 
    public void IDShouldSerializeLikeGuid() 
    { 
     Guid guid = Guid.NewGuid(); 
     ID id = (ID) guid; 
     Assert.That(ToJson(id), Is.EqualTo(ToJson(guid))); 
    } 

a wyjście drugie miejsce badawczej:

NUnit.Framework.AssertionException: Expected string length 38 but was 49. Strings differ at index 0. 
    Expected: ""7511fb9f-3515-4e95-9a04-06580753527d"" 
    But was: "{"_value":"7511fb9f-3515-4e95-9a04-06580753527d"}" 
    -----------^ 

jaki sposób serializacji mojego struct jako zwykły ciąg i uczynić mój test zdać?

Odpowiedz

10

W tym przypadku wygląda na to, że naprawdę nie chcesz JSON, chcesz mieć ciąg znaków. W tym przypadku chciałbym utworzyć interfejs tak:

interface IStringSerialized 
{ 
    String GetString(); 
} 

wdrożyć ten interfejs od typu ID (i wszystkich innych typów, które mają podobne wymagania).

[Serializable] 
class ID : IStringSerialized 
{ 
    private Guid _value; 

    public static explicit operator ID(Guid id) 
    { 
     return new ID { _value = id }; 
    } 

    public static explicit operator Guid(ID id) 
    { 
     return id._value; 
    } 

    public string GetString() 
    { 
     return this._value.ToString(); 
    } 
} 

Następnie zmodyfikować metodę serializacji do obsługi tych szczególnych przypadkach:

private static string ToJson<T>(T data) 
{ 
    IStringSerialized s = data as IStringSerialized; 

    if (s != null) 
     return s.GetString(); 

    DataContractJsonSerializer serializer 
       = new DataContractJsonSerializer(typeof(T)); 

    using (MemoryStream ms = new MemoryStream()) 
    { 
     serializer.WriteObject(ms, data); 
     return Encoding.Default.GetString(ms.ToArray()); 
    } 
} 
+0

Pominąłem pewną złożoność, aby problem był jasny, ale w prawdziwej aplikacji jest to w kontekście obiektu zawierającego listę zawierającą listę . Chcę, aby prawdziwy kod tworzył ["guid1", "guid2"], a nie [{"_value": "guid1"}, {"_value": "guid2"}]. Tak więc, niestety, to podejście nie zadziała dla mnie. Dzięki za pomysł! –

+7

Nie używaj kodowania domyślnego, ponieważ spowoduje to uszkodzenie wszystkich znaków spoza ANSI. Obecnie zajmuję się komunikatami Push telefonu komórkowego. Twój kod powinien być w stanie radzić sobie z innymi językami. Zamiast tego użyj UTF8. return Encoding.UTF8.GetString (ms.ToArray()); – midspace

0

Spróbuj użyć JavaScriptSerializer klasa będzie to zapobiec klucz, wartość uwędzić problem.

+1

, ale wtedy utracisz wszystkie atrybuty umów danych, które masz w swoim obiekcie, które chciałbyś serializować (jak emitdefaultvalue) – silver

Powiązane problemy