[英]What is the idiomatic way to find the underlying type of a JsonElement value?
.NET 6、C# 10、System.Text.Json
假設JsonElement
的ValueKind
為Number
,則JsonElement
的值可能具有int
、 decimal
、 double
等基礎類型。要找到此基礎類型,可以運行一系列測試,例如TryGetInt32()
, TryGetInt64()
、 TryGetDouble()
等。
這是最佳做法,還是有更慣用的方法?
如果您知道JSON 數字值將是整數,則使用GetInt64
/ TryGetInt64
。
GetInt32
或TryGetInt32
。 否則,只需使用Decimal
,如: JsonElement.TryGetDecimal
和JsonElement.GetDecimal
。
.NET Decimal
類型幾乎可以以全精度表示每個 JSON number
,無論它是number
,例如{ "value": 1234 }
還是非number
,例如源中的{ "value": 12.34 }
JSON。
Number.MAX_SAFE_INTEGER
(即 2 53或 9,007,199,254,740,991)。
double
精度值 - 在這種情況下,使用TryGetDouble
或GetDouble
是合適的,所以總是首先檢查您的項目要求。 一般來說,避免使用 IEEE-754 浮點類型( Single
和Double
),因為它們不能准確和精確地表示某些類型的數字,這會防止往返並導致數據丟失或損壞(例如嘗試執行( 0.001f + 0.004f ) - 0.001f
)。
假設
JsonElement
的ValueKind
為Number
,則JsonElement
的值可能具有int
、decimal
、double
等基礎類型。
這個假設是不正確的: JsonElement
類型不使用任何特定的 .NET 類型存儲或表示 JSON number
值:相反, JsonElement
結構只是源JsonDocument
的序列化 JSON 數據的視圖:所以本質上JsonElement
實際上只是一個 (經過驗證的)在一個巨大的 JSON 字符串上運行的文本。
因此,當JsonElement
的ValueKind == JsonValueKind.Number
時,它只是意味着它包裝了一個直接表示序列化 JSON number
值的字符序列,因此沒有“基礎”值表示。
...這意味着您可以使用任何TryGet...
方法從 JSON number
中獲取 .NET 數值:您唯一需要考慮的是 .NET 類型是否可以有效地表示 JSON number
與否:所以...
MAX_SAFE_INTEGER
下的非null
整數值,則使用GetInt64
(不需要TryGetInt64
)。null
整數值,則使用GetInt32
(不需要TryGetInt32
)。null
,但知道它將是一個整數值,則不要使用TryGetInt64
或TryGetInt32
,而是先檢查ValueKind == JsonValueKind.Null
,然后使用GetInt64
或GetInt32
。
null
、非整數值將導致運行時異常(您應該想要,因為它是一個意外的異常情況),而不是錯誤地假設如果TryGetInt32
返回false
則JsonElement
“必須”為null
,即錯誤的。TryGetDecimal
是可以的。 這是我編寫的一個程序,用於比較不同方法如何處理不同類型的源 JSON number
:
Test( @"{ ""value"": 0 }" );
Test( @"{ ""value"": -1 }" ); // Negative signed integer.
Test( @"{ ""value"": 512 }" );
Test( @"{ ""value"": 1.005 }" ); // Non-integer value.
Test( @"{ ""value"": 9007199254740992 }" ); // `Number.MAX_SAFE_INTEGER + 1`
Test( @"{ ""value"": 3.7e-5 }" ); // Small fractional number.
Test( @"{ ""value"": 9.99e300 }" ); // Outside the range of Decimal and Single, but within Double's range.
static void Test( String json )
{
JsonDocument doc = JsonDocument.Parse( json );
JsonElement valueProp = doc.RootElement.GetProperty("value");
valueProp.Dump();
List<( String method, Boolean ok, Object? value )> list = new();
// Decimal:
list.Add( ( nameof(valueProp.TryGetDecimal), ok: valueProp.TryGetDecimal( out Decimal dec ), value: dec ) );
// IEEE-754:
list.Add( ( nameof(valueProp.TryGetDouble), ok: valueProp.TryGetDouble( out Double dbl ), value: dbl ) );
list.Add( ( nameof(valueProp.TryGetSingle), ok: valueProp.TryGetSingle( out Single sng ), value: sng ) );
// Unsigned integers:
list.Add( ( nameof(valueProp.TryGetUInt64), ok: valueProp.TryGetUInt64( out UInt64 u64 ), value: u64 ) );
list.Add( ( nameof(valueProp.TryGetUInt32), ok: valueProp.TryGetUInt32( out UInt32 u32 ), value: u32 ) );
list.Add( ( nameof(valueProp.TryGetUInt16), ok: valueProp.TryGetUInt16( out UInt16 u16 ), value: u16 ) );
list.Add( ( nameof(valueProp.TryGetByte), ok: valueProp.TryGetByte ( out Byte u8 ), value: u8 ) );
// Signed integers:
list.Add( ( nameof(valueProp.TryGetInt64), ok: valueProp.TryGetInt64( out Int64 s64 ), value: s64 ) );
list.Add( ( nameof(valueProp.TryGetInt32), ok: valueProp.TryGetInt32( out Int32 s32 ), value: s32 ) );
list.Add( ( nameof(valueProp.TryGetInt16), ok: valueProp.TryGetInt16( out Int16 s16 ), value: s16 ) );
list.Add( ( nameof(valueProp.TryGetSByte), ok: valueProp.TryGetSByte( out SByte s8 ), value: s8 ) );
list.Dump();
}
這給了我這些結果:
輸入 JSON | TryGetDecimal |
TryGetDouble |
TryGetSingle |
TryGetUInt64 |
TryGetUInt32 |
TryGetUInt16 |
TryGetByte |
TryGetInt64 |
TryGetInt32 |
TryGetInt16 |
TryGetSByte |
---|---|---|---|---|---|---|---|---|---|---|---|
{ "value": 0 } |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
{ "value": -1 } |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | ||||
{ "value": 512 } |
512 | 512 | 512 | 512 | 512 | 512 | 512 | 512 | 512 | ||
{ "value": 1.005 } |
1.005 | 1.005 | 1.005 | ||||||||
{ "value": 9007199254740992 } |
9007199254740992 | 9007199254740992 | 9.007199E+15 | 9007199254740992 | 9007199254740992 | ||||||
{ "value": 3.7e-5 } |
0.000037 | 3.7E-05 | 3.7E-05 | ||||||||
{ "value": 9.99e300 } |
9.99E+300 | ∞ |
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.