C# JObject.Parse将数字视为int64而不是uint64。

huangapple go评论76阅读模式
英文:

C# JObject.Parse treats numbers as int64 instead of uint64

问题

If the given json str has the attribute

"seed":11405418255883340000

Error will be thrown: JsonReaderException: JSON integer 11405418255883340000 is too large or small for an Int64

As you'll notice, 11405418255883340000 is too big for int64. But is a legitimate uint64.

Is this a bug or expected? What's the easiest workaround?

英文:
var jobject = JObject.Parse(str);

If the given json str has the attribute

"seed":11405418255883340000

Error will be thrown: JsonReaderException: JSON integer 11405418255883340000 is too large or small for an Int64

As you'll notice, 11405418255883340000 is too big for int64. But is a legitimate uint64.

Is this a bug or expected? What's the easiest workaround?

答案1

得分: 1

以下是翻译好的内容:

最简单的方法可能是创建一个与您期望的负载匹配的DTO,然后将种子属性的类型设置为ulong

这是一个示例DTO:

public class Seeder {
  public ulong Seed {get;set;}
}

这是如何使用它的,而不是使用Parse:

void Main()
{
    var str = "{\"seed\":11405418255883340000}";
    var ser = new JsonSerializer();
    var jr = new JsonTextReader(new StringReader(str));
    var seed = ser.Deserialize<Seeder>(jr);
    seed.Dump();
}

这是LinqPad显示的内容:

C# JObject.Parse将数字视为int64而不是uint64。

如果我将属性类型更改回long,我会得到以下异常:

将值11405418255883340000转换为类型'System.Int64'时出错。路径'seed',行1,位置28。

请注意,您不必编写一个完全指定的DTO对象。这个也可以工作,我们只是在DTO类上没有seed属性:

void Main()
{
    var str = "{\"seed\":11405418255883340000, \"bar\": 4}";
    var ser = new JsonSerializer();
    var jr = new JsonTextReader(new StringReader(str));
    var seed = ser.Deserialize<Seeder>(jr);
    seed.Dump();
}

public class Seeder {
  public int Bar {get;set;}
}

如果您懒得做,可以将JSON负载放入在线类生成器和/或您的IDE中的工具中。有关此方面的起点,请参见:https://stackoverflow.com/a/21611680

英文:

The easiest is probably to create a DTO that matches the payload you expect and then set the type to ulong of the seed property.

Here is an example DTO:


public class Seeder {
  public ulong Seed {get;set;}
}

And here is how you use it, instead of Parse:

void Main()
{
    var str = @&quot;{&quot;&quot;seed&quot;&quot;:11405418255883340000}&quot;;
    var ser = new JsonSerializer();
    var jr = new JsonTextReader(new StringReader(str));
    var seed = ser.Deserialize&lt;Seeder&gt;(jr);
    seed.Dump();
}

This is what LinqPad shows me:

C# JObject.Parse将数字视为int64而不是uint64。

If I change the property type back to long I get this exception:

> Error converting value 11405418255883340000 to type 'System.Int64'. Path 'seed', line 1, position 28.

Note that you don't have to code a fully specified DTO object. This one works as wel, where we simply don't have the seed property on our DTO class:

void Main()
{
    var str = @&quot;{&quot;&quot;seed&quot;&quot;:11405418255883340000, &quot;&quot;bar&quot;&quot;: 4}&quot;;
    var ser = new JsonSerializer();
    var jr = new JsonTextReader(new StringReader(str));
    var seed = ser.Deserialize&lt;Seeder&gt;(jr);
    seed.Dump();
}

public class Seeder {
  public int Bar {get;set;}
}

If you are lazy you can drop the JSON payload into an online class generator and/or tooling in your IDE. See for a starting point on that: https://stackoverflow.com/a/21611680

答案2

得分: 1

你需要使用 System.Numerics 以便处理 BigInteger。默认情况下使用的是 long 而不是 ulong,所以会发生溢出。然后它会尝试将其解析为 BigInteger

JSON.Net 源代码 中的注释说

#if HAVE_BIG_INTEGER
        // 通过在单独的方法中使用 BigInteger 类型,
        // 即使 System.Numerics.BigInteger.Parse 方法丢失,运行时也可以执行 ParseNumber,这在某些版本的 Mono 中发生
        [MethodImpl(MethodImplOptions.NoInlining)]
        private static object BigIntegerParse(string number, CultureInfo culture)
        {
            return System.Numerics.BigInteger.Parse(number, culture);
        }
#endif

所以如果您可以将该库添加到您的项目中,那么它应该可以工作。

但是最好的方法是像其他答案所说的那样,使用适当的对象模型。

英文:

You need System.Numerics so that it can handle BigInteger. The default is to use long not ulong, so it will get an overflow. Then it will try to parse it as a BigInteger.

The comments in the JSON.Net source code say

#if HAVE_BIG_INTEGER
        // By using the BigInteger type in a separate method,
        // the runtime can execute the ParseNumber even if 
        // the System.Numerics.BigInteger.Parse method is
        // missing, which happens in some versions of Mono
        [MethodImpl(MethodImplOptions.NoInlining)]
        private static object BigIntegerParse(string number, CultureInfo culture)
        {
            return System.Numerics.BigInteger.Parse(number, culture);
        }
#endif

So if you can add that library to your project then it should work.

But your best bet is to just use a proper object model, like the other answer says.

huangapple
  • 本文由 发表于 2023年4月17日 13:22:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76031931.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定