2017-04-16 18 views
0

私のクラスにはcharのリストがあります。シリアライゼーションとデシリアライゼーションは期待通りに動作します。私のリストに、バイトオーダーマークを記述するcharが必要な場合。 charコードの例は56256です。したがって、以下のように簡単なテストを作成しました。charをシリアライズしてデシリアライズ

[Test] 
public void Utf8CharSerializeAndDeserializeShouldEqual() 
{ 
    UInt16 charCode = 56256; 
    char utfChar = (char)charCode; 
    using (MemoryStream ms = new MemoryStream()) 
    { 
     using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8, 1024, true)) 
     { 
      var serializer = new JsonSerializer(); 
      serializer.Serialize(writer, utfChar); 
     } 

     ms.Position = 0; 
     using (StreamReader reader = new StreamReader(ms, true)) 
     { 
      using (JsonTextReader jsonReader = new JsonTextReader(reader)) 
      { 
       var serializer = new JsonSerializer(); 
       char deserializedChar = serializer.Deserialize<char>(jsonReader); 

       Console.WriteLine($"{(int)utfChar}, {(int)deserializedChar}"); 
       Assert.AreEqual(utfChar, deserializedChar); 
       Assert.AreEqual((int)utfChar, (int)deserializedChar); 
      } 
     } 
    } 
} 

テストは、charコードが不要な場合は正常に動作します。BOM。たとえば、65(A)がこのテストに合格します。

+0

StreamWriterで任意のコードポイントを書き込むことはできませんが、BOMはもちろん特別です。どんなことでも、代理人を書くこととは違います。 StreamWriterを使ってjsonを書く必要がある場合は、少なくともjsonシリアライザがそれを保存する方法を確認するための実験を行ってください。 –

+0

確かに、私たちのAPIはストリームの書き込みをサポートしていますが、ちょっとハックしてコードを変更しました。 Json.netはStreamWriterをサポートしています。私は、charリスト(List )を持っていて、シリアル化された文字は、逆シリアル化されていません。これは重要な問題ではありませんか? –

+0

「バイトオーダーマークを記述する必要がある」または「BOMが必要ではありません」という意味がわかりません。コード・ポイント56256(U + DBC0とも呼ばれます)は、サロゲート・コード・ポイントが高いです。バイトオーダーマークとは関係ありません。 –

答えて

1

あなたの問題はJson.NETとは無関係です。あなたの問題はU+DBC0 (decimal 56256)が無効なUnicode文字で、かつ、documentationで説明したように、あなたのStreamWriterで使用Encoding.UTF8は、このような文字をエンコードしないことである。

Encoding.UTF8は、それぞれを交換するために交換用のフォールバックを使用していますUTF8Encodingオブジェクトを返します。それはエンコードできない文字列と、疑問符( "?")文字でデコードできない各バイトです。無効なUnicodeのchar値をシリアル化しようとしている場合は「あなたに、

EncoderFallbackException: Unable to translate Unicode character \uDBC0 at index 1 to specified code page. 

:あなたの試験例ではnew UTF8Encoding(true, true)Encoding.UTF8を置き換える場合

は、これを確認するには、次の例外が発生します

public static partial class TextExtensions 
{ 
    static void ToBytesWithoutEncoding(char c, out byte lower, out byte upper) 
    { 
     var u = (uint)c; 
     lower = unchecked((byte)u); 
     upper = unchecked((byte)(u >> 8)); 
    } 

    public static byte[] ToByteArrayWithoutEncoding(this char c) 
    { 
     byte lower, upper; 
     ToBytesWithoutEncoding(c, out lower, out upper); 
     return new byte[] { lower, upper }; 
    } 

    public static byte[] ToByteArrayWithoutEncoding(this ICollection<char> list) 
    { 
     if (list == null) 
      return null; 
     var bytes = new byte[checked(list.Count * 2)]; 
     int to = 0; 
     foreach (var c in list) 
     { 
      ToBytesWithoutEncoding(c, out bytes[to], out bytes[to + 1]); 
      to += 2; 
     } 
     return bytes; 
    } 

    public static char ToCharWithoutEncoding(this byte[] bytes) 
    { 
     return bytes.ToCharWithoutEncoding(0); 
    } 

    public static char ToCharWithoutEncoding(this byte[] bytes, int position) 
    { 
     if (bytes == null) 
      return default(char); 
     char c = default(char); 
     if (position < bytes.Length) 
      c += (char)bytes[position]; 
     if (position + 1 < bytes.Length) 
      c += (char)((uint)bytes[position + 1] << 8); 
     return c; 
    } 

    public static List<char> ToCharListWithoutEncoding(this byte[] bytes) 
    { 
     if (bytes == null) 
      return null; 
     var chars = new List<char>(bytes.Length/2 + bytes.Length % 2); 
     for (int from = 0; from < bytes.Length; from += 2) 
     { 
      chars.Add(bytes.ToCharWithoutEncoding(from)); 
     } 
     return chars; 
    } 
} 

次に、次のようにテストメソッドを変更します。

public void Utf8JsonCharSerializeAndDeserializeShouldEqualFixed() 
    { 
     Utf8JsonCharSerializeAndDeserializeShouldEqualFixed((char)56256); 
    } 

    public void Utf8JsonCharSerializeAndDeserializeShouldEqualFixed(char utfChar) 
    { 
     byte[] data; 

     using (MemoryStream ms = new MemoryStream()) 
     { 
      using (StreamWriter writer = new StreamWriter(ms, new UTF8Encoding(true, true), 1024)) 
      { 
       var serializer = new JsonSerializer(); 
       serializer.Serialize(writer, utfChar.ToByteArrayWithoutEncoding()); 
      } 
      data = ms.ToArray(); 
     } 

     using (MemoryStream ms = new MemoryStream(data)) 
     { 
      using (StreamReader reader = new StreamReader(ms, true)) 
      { 
       using (JsonTextReader jsonReader = new JsonTextReader(reader)) 
       { 
        var serializer = new JsonSerializer(); 
        char deserializedChar = serializer.Deserialize<byte[]>(jsonReader).ToCharWithoutEncoding(); 

        //Console.WriteLine(string.Format("{0}, {1}", utfChar, deserializedChar)); 
        Assert.AreEqual(utfChar, deserializedChar); 
        Assert.AreEqual((int)utfChar, (int)deserializedChar); 
       } 
      } 
     } 
    } 

それとも、あなたには、いくつかのコンテナクラスでList<char>性質を持っている場合は、以下のコンバータ作成することができます。どちらの場合も

public class RootObject 
{ 
    [JsonConverter(typeof(CharListConverter))] 
    public List<char> Characters { get; set; } 
} 

public class CharListConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(List<char>); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var bytes = serializer.Deserialize<byte[]>(reader); 
     return bytes.ToCharListWithoutEncoding(); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var list = (ICollection<char>)value; 
     var bytes = list.ToByteArrayWithoutEncoding(); 
     serializer.Serialize(writer, bytes); 
    } 
} 

そして、次のようにそれを適用しますJson.NETはバイト配列をBase64としてエンコードします。

関連する問題