내 수업에 문자 목록이 있습니다. 직렬화 및 역 직렬화는 예상대로 작동합니다. 내 목록에 바이트 순서 표시를 설명하는 데 필요한 문자가 포함되어 있으면. 예제 char 코드는 56256입니다. 그래서이 질문은 아래와 같이 간단한 테스트를 생성했습니다.
[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);
}
}
}
}
BOM에 char 코드가 필요하지 않은 경우 테스트가 정상적으로 작동합니다. 예를 들어 65 (A)는이 테스트를 통과합니다.
귀하의 문제는 Json.NET과 관련이 없습니다. 귀하의 문제가있다 U+DBC0
(십진수 56256)이 에 설명 된대로, 잘못된 유니 코드 문자이며, 문서 의 Encoding.UTF8
에 의해 사용하여 StreamWriter
이러한 문자를 인코딩하지 않습니다 :
Encoding.UTF8
UTF8Encoding
대체 대체를 사용하여 인코딩 할 수없는 각 문자열과 디코딩 할 수없는 각 바이트를 물음표 ( "?") 문자로 바꾸는 객체를 반환합니다 .
바꿀 경우이를 확인하려면 Encoding.UTF8
함께 new UTF8Encoding(true, true)
테스트 예제에서 다음과 같은 예외를 얻을 것이다 :
EncoderFallbackException: Unable to translate Unicode character \uDBC0 at index 1 to specified code page.
유효하지 않은 유니 코드 char
값 을 직렬화 하려면 다음을 사용하여 바이트 배열과 같이 수동으로 인코딩해야합니다.
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 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);
}
}
그리고 다음과 같이 적용하십시오.
public class RootObject
{
[JsonConverter(typeof(CharListConverter))]
public List<char> Characters { get; set; }
}
두 경우 모두 Json.NET은 바이트 배열을 Base64로 인코딩합니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다