Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用JsonConvert将JSON反序列化到VB.NET中的数据表中_.net_Json_Vb.net_Json.net_Deserialization - Fatal编程技术网

使用JsonConvert将JSON反序列化到VB.NET中的数据表中

使用JsonConvert将JSON反序列化到VB.NET中的数据表中,.net,json,vb.net,json.net,deserialization,.net,Json,Vb.net,Json.net,Deserialization,我正在使用VB.NET中的以下语句将JSON反序列化到数据表中 Dim _dt As DataTable = JsonConvert.DeserializeObject(Of DataTable)(myRecords) myRecords是一个JSON字符串 它工作正常,但myRecords有一些数字属性,如{“PhoneNo”:“123456789”,“ID”:“46541”},反序列化后,这些属性将转换为数据类型为string的列 如何将它们反序列化为一个数字?myRecords正在动态填

我正在使用VB.NET中的以下语句将JSON反序列化到数据表中

Dim _dt As DataTable = JsonConvert.DeserializeObject(Of DataTable)(myRecords)
myRecords是一个JSON字符串

它工作正常,但myRecords有一些数字属性,如{“PhoneNo”:“123456789”,“ID”:“46541”},反序列化后,这些属性将转换为数据类型为string的列


如何将它们反序列化为一个数字?myRecords正在动态填充,因此我无法硬编码。

Json.NET为
“PhoneNo”创建字符串类型列的原因是:“123456789”
是因为
“123456789”
实际上是根据。数值文字如下所示,其值周围不带双引号:
123456789
。您确定这些属性将始终是数字字符串吗?并不是所有的电话号码都是数字的,例如,所以硬编码似乎是不明智的

也就是说,如果您确定这些属性始终是数字字符串,并且希望Json.NET为它们创建数字
DataTable
列,那么您需要提前告诉它这些列的所需类型。一种选择是从适当的模式创建一个。在这种情况下,
JsonConvert.DeserializeObject(属于TTypedDataable)(myRecords)
将创建一个具有所需列类型的
DataTable
子类

另一个选项是使用一组适当的列手动创建
DataTable
,然后从JSON填充该表。不幸的是,在预分配的
数据表上无法工作,因此需要直接调用。这可以通过以下扩展方法完成:

Public Module JsonExtensions
    Public Sub PopulateDataTable(json As String, target As DataTable, Optional settings As JsonSerializerSettings = Nothing)
        Using reader = New JsonTextReader(New StringReader(json))
            Do
                If reader.TokenType = JsonToken.StartArray Then
                    ' Populate the table
                    Dim converter = New DataTableConverter()
                    converter.ReadJson(reader, target.GetType(), target, JsonSerializer.CreateDefault(settings))
                End If
            Loop While reader.Read()
        End Using
    End Sub
End Module
然后按如下方式使用:

        Dim _dt = New DataTable()
        _dt.Columns.Add("PhoneNo", GetType(Long))
        _dt.Columns.Add("ID", GetType(Long))
        JsonExtensions.PopulateDataTable(myRecords, _dt)
        Dim token = JToken.Parse(myRecords)
        JsonExtensions.TryConvertColumnsToNullableLong(token)
        Dim _dt = token.ToObject(Of DataTable)()
例如

你也写过,我不会硬编码。如果您确实事先不知道哪些具有字符串值的列实际上应该被反序列化为数字类型,那么您可以通过将JSON加载到一个数组中,按名称对所有属性值进行分组,并为每个组检查组中的所有值是否都是可转换为数字的字符串来预处理JSON。如果所有都是可转换的,则可以进行转换。但如果只有一些是可转换的,则不应进行转换,因为这将破坏Json.NET的类型推断算法。可以使用以下扩展方法完成此操作:

Public Module JsonExtensions
    Private ReadOnly NumberTypes = New JTokenType() {JTokenType.[Integer], JTokenType.Float, JTokenType.[String], JTokenType.Comment, JTokenType.Raw, JTokenType.[Boolean]}

    Private Function ValidateToken(o As JToken, validTypes As JTokenType(), nullable As Boolean) As Boolean
        Return (Array.IndexOf(validTypes, o.Type) <> -1) OrElse (nullable AndAlso (o.Type = JTokenType.Null OrElse o.Type = JTokenType.Undefined))
    End Function

    <System.Runtime.CompilerServices.Extension> _
    Public Function CanConvertToNullableLong(token As JToken) As Boolean
        ' Reverse engineered from 
        ' public static explicit operator long?(JToken value)
        ' https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Linq/JToken.cs#L1045
        If token Is Nothing OrElse token.Type = JTokenType.Null OrElse token.Type = JTokenType.Boolean Then
            Return True
        End If
        If Not ValidateToken(token, NumberTypes, True) Then
            Return False
        End If
        Dim jValue = TryCast(token, JValue)
        If jValue Is Nothing Then
            Return False
        End If
        If TypeOf jValue.Value Is BigInteger Then
            Dim i = CType(jValue.Value, BigInteger)
            Return i <= Long.MaxValue AndAlso i >= Long.MinValue
        End If
        Dim s = CType(jValue, String)
        Dim v As Long
        Return Long.TryParse(s, NumberStyles.Number, NumberFormatInfo.InvariantInfo, v)
    End Function

    Public Sub TryConvertColumnsToNullableLong(root As JToken)
        If TypeOf root Is JContainer Then
            ' If ALL columns values of a given name can be converted from string to long, then do so.
            ' Do not convert columns where some but not all are convertable.
            For Each group In DirectCast(root, JContainer) _
                .Descendants() _
                .OfType(Of JProperty)() _
                .GroupBy(Function(p) p.Name) _
                .Where(Function(g) g.All(Function(p) (p.Value.Type = JTokenType.String Or p.Value.Type = JTokenType.Null) AndAlso p.Value.CanConvertToNullableLong()))
                For Each p In group
                    p.Value = CType(p.Value, System.Nullable(Of Long))
                Next
            Next
        End If
    End Sub
End Module
例如


但是我不确定我会推荐这个。JSON值是字符串的事实表明,在生成JSON的数据库中,这些值可以是任意的字符串。如果是这样,在转换为
long
的过程中进行黑客攻击可能会在以后非数值开始进入数据库时导致问题。

Json.NET为
“PhoneNo”创建字符串类型列的原因是:“123456789”
实际上是根据。数值文字如下所示,其值周围不带双引号:
123456789
。您确定这些属性将始终是数字字符串吗?并不是所有的电话号码都是数字的,例如,所以硬编码似乎是不明智的

也就是说,如果您确定这些属性始终是数字字符串,并且希望Json.NET为它们创建数字
DataTable
列,那么您需要提前告诉它这些列的所需类型。一种选择是从适当的模式创建一个。在这种情况下,
JsonConvert.DeserializeObject(属于TTypedDataable)(myRecords)
将创建一个具有所需列类型的
DataTable
子类

另一个选项是使用一组适当的列手动创建
DataTable
,然后从JSON填充该表。不幸的是,在预分配的
数据表上无法工作,因此需要直接调用。这可以通过以下扩展方法完成:

Public Module JsonExtensions
    Public Sub PopulateDataTable(json As String, target As DataTable, Optional settings As JsonSerializerSettings = Nothing)
        Using reader = New JsonTextReader(New StringReader(json))
            Do
                If reader.TokenType = JsonToken.StartArray Then
                    ' Populate the table
                    Dim converter = New DataTableConverter()
                    converter.ReadJson(reader, target.GetType(), target, JsonSerializer.CreateDefault(settings))
                End If
            Loop While reader.Read()
        End Using
    End Sub
End Module
然后按如下方式使用:

        Dim _dt = New DataTable()
        _dt.Columns.Add("PhoneNo", GetType(Long))
        _dt.Columns.Add("ID", GetType(Long))
        JsonExtensions.PopulateDataTable(myRecords, _dt)
        Dim token = JToken.Parse(myRecords)
        JsonExtensions.TryConvertColumnsToNullableLong(token)
        Dim _dt = token.ToObject(Of DataTable)()
例如

你也写过,我不会硬编码。如果您确实事先不知道哪些具有字符串值的列实际上应该被反序列化为数字类型,那么您可以通过将JSON加载到一个数组中,按名称对所有属性值进行分组,并为每个组检查组中的所有值是否都是可转换为数字的字符串来预处理JSON。如果所有都是可转换的,则可以进行转换。但如果只有一些是可转换的,则不应进行转换,因为这将破坏Json.NET的类型推断算法。可以使用以下扩展方法完成此操作:

Public Module JsonExtensions
    Private ReadOnly NumberTypes = New JTokenType() {JTokenType.[Integer], JTokenType.Float, JTokenType.[String], JTokenType.Comment, JTokenType.Raw, JTokenType.[Boolean]}

    Private Function ValidateToken(o As JToken, validTypes As JTokenType(), nullable As Boolean) As Boolean
        Return (Array.IndexOf(validTypes, o.Type) <> -1) OrElse (nullable AndAlso (o.Type = JTokenType.Null OrElse o.Type = JTokenType.Undefined))
    End Function

    <System.Runtime.CompilerServices.Extension> _
    Public Function CanConvertToNullableLong(token As JToken) As Boolean
        ' Reverse engineered from 
        ' public static explicit operator long?(JToken value)
        ' https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Linq/JToken.cs#L1045
        If token Is Nothing OrElse token.Type = JTokenType.Null OrElse token.Type = JTokenType.Boolean Then
            Return True
        End If
        If Not ValidateToken(token, NumberTypes, True) Then
            Return False
        End If
        Dim jValue = TryCast(token, JValue)
        If jValue Is Nothing Then
            Return False
        End If
        If TypeOf jValue.Value Is BigInteger Then
            Dim i = CType(jValue.Value, BigInteger)
            Return i <= Long.MaxValue AndAlso i >= Long.MinValue
        End If
        Dim s = CType(jValue, String)
        Dim v As Long
        Return Long.TryParse(s, NumberStyles.Number, NumberFormatInfo.InvariantInfo, v)
    End Function

    Public Sub TryConvertColumnsToNullableLong(root As JToken)
        If TypeOf root Is JContainer Then
            ' If ALL columns values of a given name can be converted from string to long, then do so.
            ' Do not convert columns where some but not all are convertable.
            For Each group In DirectCast(root, JContainer) _
                .Descendants() _
                .OfType(Of JProperty)() _
                .GroupBy(Function(p) p.Name) _
                .Where(Function(g) g.All(Function(p) (p.Value.Type = JTokenType.String Or p.Value.Type = JTokenType.Null) AndAlso p.Value.CanConvertToNullableLong()))
                For Each p In group
                    p.Value = CType(p.Value, System.Nullable(Of Long))
                Next
            Next
        End If
    End Sub
End Module
例如


但是我不确定我会推荐这个。JSON值是字符串的事实表明,在生成JSON的数据库中,这些值可以是任意的字符串。如果是这样的话,在转换为
long
时进行黑客攻击可能会在以后非数值开始进入数据库时导致问题。

json从何而来?它看起来像什么?一般来说,电话号码是字符串:你不能加或减,所以它们不是数字。如果ID被序列化为字符串,那么您可能需要编写一个转换器将其强制转换为INT,json从何而来?它看起来像什么?一般来说,电话号码是字符串:你不能加或减,所以它们不是数字。如果ID被序列化为字符串,则可能需要编写一个转换器来强制将其转换为int