You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#浮点序列化到JavaScript数字的兼容问题及自定义转换器疑问

问题背景

我用Newtonsoft.Json序列化自定义类作为Web请求的Payload,通过哈希校验保证数据一致性。序列化代码是JsonConvert.SerializeObject(_report,settings);,配置如下:

public static JsonSerializerSettings GetJsonSettings(){
    JsonSerializerSettings settings = new JsonSerializerSettings();
    settings.DefaultValueHandling = DefaultValueHandling.Include;
    settings.MissingMemberHandling = MissingMemberHandling.Ignore;
    settings.NullValueHandling = NullValueHandling.Ignore;
    settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
    settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    return settings;
}

待序列化的类示例:

public class FlightLogEntry {
    public long timestamp;
    public Vector3 position;
    public float speedX;
    public float speedZ;
    public float speedMagnitude;
    public float battery;

    public FlightLogEntry() {

    }
}

C#序列化后,整数型浮点数会保留.0(比如0.0),但后端JavaScript用JSON.stringify处理后,这些值会变成整数(比如0),导致两边哈希值不一致。之前试过用自定义转换器去掉.0解决哈希问题,但备份文件反序列化时,JSON里的整数无法转成float类型,引发错误。

问题解答

1. 处理C#浮点数1.0在JavaScript中变为1的兼容问题的更优方案

有两种可靠的思路:

思路一:统一序列化规则,让C#输出和JS一致的JSON

实现一个自定义JsonConverter<float>,序列化时把整数型浮点数(比如0.0、1.0)输出为整数,非整数型浮点数正常输出;反序列化时同时兼容整数和浮点数格式的JSON值。这样C#和JS序列化结果完全一致,哈希校验就能通过,同时反序列化也不会出错。

示例转换器代码:

public class FloatConverter : JsonConverter<float>
{
    public override void WriteJson(JsonWriter writer, float value, JsonSerializer serializer)
    {
        // 判断是否是整数型浮点数
        if (value == Math.Floor(value))
        {
            writer.WriteValue((long)value);
        }
        else
        {
            writer.WriteValue(value);
        }
    }

    public override float ReadJson(JsonReader reader, Type objectType, float existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 兼容整数和浮点数类型的JSON值
        if (reader.TokenType == JsonToken.Integer)
        {
            return Convert.ToSingle((long)reader.Value);
        }
        else if (reader.TokenType == JsonToken.Float)
        {
            return Convert.ToSingle(reader.Value);
        }
        throw new JsonSerializationException($"Unexpected token type {reader.TokenType} for float value");
    }
}

然后在GetJsonSettings里添加转换器:

settings.Converters.Add(new FloatConverter());

思路二:在C#端模拟JS的JSON.stringify行为计算哈希

如果不想修改序列化输出,可以在C#计算哈希前,先把序列化后的JSON做一次“JS风格”的处理——把所有\.0(?=[,}\]])格式的字符串替换成空,再计算哈希。这样计算出的哈希和JS端基于JSON.stringify结果计算的哈希一致,同时不影响备份文件的反序列化(因为原始序列化结果保留了.0)。

示例处理代码:

string csharpJson = JsonConvert.SerializeObject(_report, settings);
// 替换整数型浮点数的.0
string jsStyleJson = Regex.Replace(csharpJson, @"\.0(?=[,}\]])", "");
// 基于jsStyleJson计算哈希
byte[] hashBytes = SHA256.HashData(Encoding.UTF8.GetBytes(jsStyleJson));
string hash = Convert.ToHexString(hashBytes);

2. 自定义转换器的ReadJson方法中识别目标类型

完全可以。自定义转换器的ReadJson方法参数里的objectType就是当前要反序列化的目标类型(比如typeof(float)),你可以根据这个类型来处理不同的JSON值:

比如在通用转换器中:

public class NumberConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(float) || objectType == typeof(double);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Integer)
        {
            if (objectType == typeof(float))
            {
                return Convert.ToSingle((long)reader.Value);
            }
            else if (objectType == typeof(double))
            {
                return Convert.ToDouble((long)reader.Value);
            }
        }
        else if (reader.TokenType == JsonToken.Float)
        {
            return Convert.ChangeType(reader.Value, objectType);
        }
        throw new JsonSerializationException($"Cannot convert token {reader.TokenType} to {objectType}");
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // 序列化逻辑按需实现
        var floatValue = Convert.ToSingle(value);
        if (floatValue == Math.Floor(floatValue))
        {
            writer.WriteValue((long)floatValue);
        }
        else
        {
            writer.WriteValue(floatValue);
        }
    }
}

如果是泛型转换器(比如JsonConverter<float>),objectType固定为typeof(float),直接处理即可,就像第一个问题里的示例转换器那样。

内容的提问来源于stack exchange,提问作者StewVanB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 22:09:24