Как разрешить InvalidCastException после перевода запроса LINQ-to-JSON с С# на VB.NET?

Я пытаюсь использовать код от этот ответ С# до Преобразовать вложенный JSON в CSV, но мой проект VB.NET. Я пробовал несколько онлайн-конвертеров, но без особого успеха. Версия C# работает отлично, но версии VB.NET выдают InvalidCastException. В чем может быть проблема?

Мой JSON:

  {
  "Response": [
    [
      {
        "id": 136662306,
        "symbol": "aaa",
        "status": "ACTIVE",
        "base": "731.07686321",
        "amount": "6.95345994",
        "timestamp": "1524781083.0",
        "swap": "0.0",
        "pl": "5127.4352653395923394"
      },
      {
        "id": 137733525,
        "symbol": "bbb",
        "status": "ACTIVE",
        "base": "636.75093128",
        "amount": "1.1",
        "timestamp": "1531902193.0",
        "swap": "0.0",
        "pl": "687.800226608"
      }
    ]
  ]
}

Моя версия С#, которая работает

JObject obj = JObject.Parse(json);

// Collect column titles: all property names whose values are of type JValue, distinct, in order of encountering them.
var values = obj.DescendantsAndSelf()
    .OfType<JProperty>()
    .Where(p => p.Value is JValue)
    .GroupBy(p => p.Name)
    .ToList();

var columns = values.Select(g => g.Key).ToArray();

// Filter JObjects that have child objects that have values.
var parentsWithChildren = values.SelectMany(g => g).SelectMany(v => v.AncestorsAndSelf().OfType<JObject>().Skip(1)).ToHashSet();

// Collect all data rows: for every object, go through the column titles and get the value of that property in the closest ancestor or self that has a value of that name.
var rows = obj
    .DescendantsAndSelf()
    .OfType<JObject>()
    .Where(o => o.PropertyValues().OfType<JValue>().Any())
    .Where(o => o == obj || !parentsWithChildren.Contains(o)) // Show a row for the root object + objects that have no children.
    .Select(o => columns.Select(c => o.AncestorsAndSelf()
        .OfType<JObject>()
        .Select(parent => parent[c])
        .Where(v => v is JValue)
        .Select(v => (string)v)
        .FirstOrDefault())
        .Reverse() // Trim trailing nulls
        .SkipWhile(s => s == null)
        .Reverse());

// Convert to CSV
var csvRows = new[] { columns }.Concat(rows).Select(r => string.Join(",", r));
var csv = string.Join("\n", csvRows);

Моя версия VB.NET дает следующее исключение:

System.InvalidCastException: 'Unable to cast object of type 'WhereSelectEnumerableIterator`2

Dim obj As JObject = Nothing
obj = JObject.Parse(json)

Dim values = obj.DescendantsAndSelf().
                 OfType(Of JProperty)().
                 Where(Function(p) TypeOf p.Value Is JValue).
                 GroupBy(Function(p) p.Name).ToList()
Dim columns = values.[Select](Function(g) g.Key).ToArray()
Dim parentsWithChildren = values.SelectMany(Function(g) g).
                                            SelectMany(Function(v) v.AncestorsAndSelf().
                                            OfType(Of JObject)().Skip(1)).ToHashSet()
Dim rows = obj.DescendantsAndSelf().
               OfType(Of JObject)().
               Where(Function(o) o.PropertyValues().
               OfType(Of JValue)().Any()).
               Where(Function(o) o = obj OrElse Not parentsWithChildren.Contains(o)).
               [Select](Function(o) columns.[Select](Function(c) o.AncestorsAndSelf().
                    OfType(Of JObject)().
                    [Select](Function(parent) parent(c)).
                    Where(Function(v) TypeOf v Is JValue).
                    [Select](Function(v) CStr(v)).
                    FirstOrDefault()).
                    Reverse().
                    SkipWhile(Function(s) s Is Nothing).
                    Reverse())
Dim csvRows = {columns}.Concat(rows).[Select](Function(r) String.Join(",", r))   ' HERE IS WHERE THE EXCEPTION OCCURS
Dim csv = String.Join(vbLf, csvRows)

Исключение

{"Unable to cast object of type 'WhereSelectEnumerableIterator`2[Newtonsoft.Json.Linq.JObject,System.Collections.Generic.IEnumerable`1[System.String]]' to type 'System.Collections.Generic.IEnumerable`1[System.String[]]'."}

Я не знаю VB от моей задницы, но эта строка не ошибается If arr Is Nothing Then obj = JObject.Parse(arr.ToString()). Если массив равен нулю, тогда array.tostring()???

Simon Wilson 19.05.2019 22:41

Возможно, вы могли бы добавить новую библиотеку на С#, и решение сможет работать с обоими языками одновременно.

Mate 19.05.2019 23:03

Кстати, если вы не знаете, является ли корневой контейнер JSON массивом или объектом, используйте JToken.Parse, а затем выполните приведение к JContainer, чтобы сделать DescendantsAndSelf(). Подробнее см. в JSON.NET: зачем вообще использовать JToken?.

dbc 19.05.2019 23:06

Я перешел по ссылке, которую вы даете для кода С#, но я не вижу ничего, что соответствовало бы коду VB.NET, который вы показываете. Не могли бы вы предоставить код C#?

RobertBaron 19.05.2019 23:26

Я только что отредактировал и добавил весь необходимый код

SparcU 20.05.2019 00:10

Упрощенный VB.NET тоже

SparcU 20.05.2019 00:16

Вам нужно сделать { columns.AsEnumerable() }.Concat(rows) вместо просто {columns}.Concat(rows), см. dotnetfiddle.net/jFXvxw. Я не могу объяснить, почему, однако, кажется, что вывод типа VB.NET делает что-то странное при использовании метода расширения Linq Concat для объединения массива строк с ленивым перечислением строк. Добавление в ToEnumerable() исправляет вывод типа (хотя на самом деле это ничего не делает, это просто преобразование). См. dotnetfiddle.net/jFXvxw

dbc 20.05.2019 02:35

Простой минимальный воспроизводимый пример проблемы, которая не имеет ничего общего с JSON: рабочий c# здесь: dotnetfiddle.net/vcZsjV, нерабочий vb.net здесь: dotnetfiddle.net/k6Z5tE, исправлен vb.net здесь: dotnetfiddle.net/sbi3oA Не понимаю, зачем добавлять AsEnumerable() для изменения 2d зубчатого массива строк в массив перечисляемых строк ничего не меняет. Я почти склонен задать отдельный вопрос об этом.

dbc 20.05.2019 03:05

@dbc Да, похоже на ошибку. Если вы перед вызовом IEnumerable(Of IEnumerable(Of String)) приведете зубчатый массив к .Concat(), он будет работать нормально (даже несмотря на то, что все, что мы сделали, — это приведение неявный) (что, по-моему, в основном и делает AsEnumberable()?). Я предполагаю, что разрешение перегрузки не может найти соответствующую перегрузку метода расширения?

41686d6564 20.05.2019 03:43

Вы правы, просто добавление DirectCast решает проблему: DirectCast(columns, IEnumerable(Of IEnumerable(Of String))).Concat(rows), см. dotnetfiddle.net/tWnzTA. Довольно загадочный и, возможно, стоящий второго вопроса. Вы хотите это спросить?

dbc 20.05.2019 03:47

@dbc Умм, конечно! Позвольте мне собрать пример.

41686d6564 20.05.2019 04:00

@AhmedAbdelhameed тем временем я добавил ответ здесь, так что этот вопрос может быть решен.

dbc 20.05.2019 04:18
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
12
261
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы {columns}.Concat(rows) работал, кажется, вам нужно добавить явный вызов AsEnumerable(), чтобы убедиться, что тип TSource для Enumerable.Concat(IEnumerable<TSource>, IEnumerable<TSource>) выводится правильно:

Dim csvRows = { columns.AsEnumerable() }.Concat(rows) _
                .Select(Function(r) String.Join(",", r))

Исправлена ​​рабочий пример №1 здесь.

DirectCast({columns}, IEnumerable(Of IEnumerable(Of String))) также работает, как указано в Комментарии автором Ахмед Абдельхамид:

Dim csvRows = DirectCast({columns}, IEnumerable(Of IEnumerable(Of String))).Concat(rows) _
                .Select(Function(r) String.Join(",", r))

Исправлена ​​рабочий пример #2 здесь.

Вызов Enumerable.Concat(Of IEnumerable(Of String)) явно, без использования логических выводов, также работает:

Dim csvRows = Enumerable.Concat(Of IEnumerable(Of String))({columns}, rows) _
                .Select(Function(r) String.Join(",", r))

Исправлена ​​рабочий пример №3 здесь.

Таким образом, весь ваш код должен выглядеть так:

Dim obj As JObject = JObject.Parse(json)

Dim values = obj.DescendantsAndSelf().OfType(Of JProperty)().Where(Function(p) TypeOf p.Value Is JValue).GroupBy(Function(p) p.Name).ToList()
Dim columns = values.[Select](Function(g) g.Key).ToArray()

Dim parentsWithChildren = values.SelectMany(Function(g) g).SelectMany(Function(v) v.AncestorsAndSelf().OfType(Of JObject)().Skip(1)).ToHashSet()

Dim rows = obj.DescendantsAndSelf() _
                    .OfType(Of JObject)() _
                    .Where(Function(o) o.PropertyValues().OfType(Of JValue)().Any()) _
                    .Where(Function(o) o.Equals(obj) OrElse Not parentsWithChildren.Contains(o)) _
                    .Select(Function(o) columns.Select(Function(c) _
                                                    o.AncestorsAndSelf() _
                                                    .OfType(Of JObject)() _
                                                    .Select(Function(parent) parent(c)) _
                                                    .OfType(Of JValue)() _
                                                    .Select(Function(v) CStr(v)) _
                                                    .FirstOrDefault()) _
                                                .Reverse() _
                                                .SkipWhile(Function(s) s Is Nothing) _
                                                .Reverse())

Dim csvRows =  { columns.AsEnumerable() }.Concat(rows) _
                .Select(Function(r) String.Join(",", r)) 
Dim csv = String.Join(vbLf, csvRows)        

Другие вопросы по теме