对象转成json后转成byte[]后在转成string会提示序列化失败,第一个字符是问号

问题复现

一个对象需要转成json 后转成byte[]后经过网络传输,后再次反序列化为对象,但是最后反序列的时候会报错,打印json发现开头是一个问号

省流

使用这个进行反序列化

csharp 复制代码
     /// <summary>
     /// 反序列化方法
     /// </summary>
     /// <typeparam name="T"></typeparam>
     /// <param name="json"></param>
     /// <returns></returns>
     public static T Deserialize<T>(string json) where T : Message, new()
     {
         return JsonConvert.DeserializeObject<T>(json.TrimStart('\uFEFF'));

     }

问题代码

一个对象

csharp 复制代码
using System.Threading;

namespace SocketTools
{
    public class TextMessage : Message
    {

        private string message;

        public string Message { get => message; set => message = value; }

        public TextMessage()
        {

        }


        public TextMessage(string userName, string targetName, string sendTime, string message) : base(userName, targetName, sendTime, MessageType.Text)
        {
            this.message = message;
        }
    }

父类

csharp 复制代码
using Newtonsoft.Json;

namespace SocketTools
{

    public enum MessageType
    {
        Connection = 0,
        Text,
        Image,
        Mixed,
        Recall,
        File,

    }

    public class Message
    {
        private string userName;
        private string targetName;
        private string sendTime;
        private MessageType messageType;

        public string UserName { get => userName; set => userName = value; }
        public string TargetName { get => targetName; set => targetName = value; }
        public string SendTime { get => sendTime; set => sendTime = value; }
        public MessageType MessageType { get => messageType; set => messageType = value; }

        public Message()
        {

        }

        public Message(string userName, string targetName, string sendTime, MessageType messageType)
        {
            UserName = userName;
            TargetName = targetName;
            SendTime = sendTime;
            MessageType = messageType;
        }

       // 序列化方法
       public static string Serialize(Message message)
       {
           return JsonConvert.SerializeObject(message);
       }

       // 反序列化方法
       public static T Deserialize<T>(string json) where T : Message, new()
       { 
   return JsonConvert.DeserializeObject<T>(json );
  
       }
     

    }

}

}

执行代码

ini 复制代码
using SocketTools;
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace FunctionalTesting
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            string msg = "消息内容Q1_2_end";
            string userName = "AAAAAAAAAAAAAAAA";
            string targetUserName = "CCCCCCCCCCCCCCCC";


            TextMessage textMessage = new TextMessage(userName,
                targetUserName,
                DateTime.Now.ToString("yy-MM-dd-H:m:s"),
                msg);

            // 按照指定的格式创建消息字符串
            string message = Message.Serialize(textMessage);
            Console.WriteLine(message);
            // 将消息字符串转换为字节流
            byte[] data;
            using (MemoryStream ms = new MemoryStream())
            {
                using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
                {
                    sw.Write(message);
                    sw.Flush();
                    ms.Position = 0;
                    data = ms.ToArray();
                }
            }
            string data2 = Encoding.UTF8.GetString(data);
            Console.WriteLine(data2);
            data2 = Regex.Replace(data2, @"^\s+", "");
            Console.WriteLine(data2);

            var d = Message.Deserialize<TextMessage>(data2);
            Console.WriteLine(d.TargetName);
            Console.WriteLine(d.UserName);
            Console.WriteLine(d.MessageType);
            Console.ReadLine();

        }
    }
}

执行后的效果

执行之后会输出

ruby 复制代码
?{"Message":"消息内容Q1_2_end","UserName":"AAAAAAAAAAAAAAAA","TargetName":"CCCCCCCCCCCCCCCC","SendTime":"23-12-04-1:14:43","MessageType":1}

错误日志:

ini 复制代码
Newtonsoft.Json.JsonReaderException
  HResult=0x80131500
  Message=Unexpected character encountered while parsing value: . Path '', line 0, position 0.

但是打印原本的数据是没有开头的问号的,

解决方式

修改反序列化的代码,去除第一个前导字符即可,或者使用字符串的判断,如果第一个字符不是{或者[ 就去除第一个字符

csharp 复制代码
  // 反序列化方法
      public static T Deserialize<T>(string json) where T : Message, new()
      { 
     return JsonConvert.DeserializeObject<T>(json.TrimStart('\uFEFF'));
 
      }

去除字符串

csharp 复制代码
      public static T Deserialize<T>(string json) where T : Message, new()
      { 
          if (json[0] == '{' || json[0] == '[')
          {
          }
          else
          {
              json = json.Remove(0, 1);
          }
          return JsonConvert.DeserializeObject<T>(json);
      }

问题原因

零宽度不中断空格(Unicode U+FEFF)字符,也称为 BOM(Byte Order Mark),在文本文件中用于表示字节顺序。它通常出现在使用 Unicode 编码的文本文件或数据流的开头。

在处理多字节编码时,需要知道每个字符的字节顺序。例如,在 UTF-16 编码中,一个字符由两个字节组成,而这两个字节的顺序可能会根据不同的系统和平台有所不同。为了明确表示字节顺序,引入了 BOM 字符。

BOM 字符 U+FEFF 可以作为文件的前导字符,允许解析器识别文件的字节顺序。当解析器遇到 U+FEFF 时,它可以确定字节顺序并正确地解码文件中的其余字符。

在某些情况下,尤其是在网络通信、数据库存储或其他形式的数据交换中,BOM 字符可能被无意间包含在字符串中,这可能导致解析错误。因此,有必要在处理这些字符串之前检查并移除任何不需要的 BOM 字符。

相关推荐
Victor35610 小时前
MongoDB(2)MongoDB与传统关系型数据库的主要区别是什么?
后端
JaguarJack10 小时前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端·php·服务端
BingoGo10 小时前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端
Victor35610 小时前
MongoDB(3)什么是文档(Document)?
后端
牛奔12 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌17 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX18 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了18 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法19 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
Moment19 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端