あなたの問題は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としてエンコードします。
StreamWriterで任意のコードポイントを書き込むことはできませんが、BOMはもちろん特別です。どんなことでも、代理人を書くこととは違います。 StreamWriterを使ってjsonを書く必要がある場合は、少なくともjsonシリアライザがそれを保存する方法を確認するための実験を行ってください。 –
確かに、私たちのAPIはストリームの書き込みをサポートしていますが、ちょっとハックしてコードを変更しました。 Json.netはStreamWriterをサポートしています。私は、charリスト(List)を持っていて、シリアル化された文字は、逆シリアル化されていません。これは重要な問題ではありませんか? –
「バイトオーダーマークを記述する必要がある」または「BOMが必要ではありません」という意味がわかりません。コード・ポイント56256(U + DBC0とも呼ばれます)は、サロゲート・コード・ポイントが高いです。バイトオーダーマークとは関係ありません。 –