In order for {columns}.Concat(rows)
to work, it seems you need to add an explicit call to AsEnumerable()
in order to make sure the type TSource
for Enumerable.Concat(IEnumerable<TSource>, IEnumerable<TSource>)
is inferred correctly:
Dim csvRows = { columns.AsEnumerable() }.Concat(rows) _
.Select(Function(r) String.Join(",", r))
Fixed fiddle #1 here.
A DirectCast({columns}, IEnumerable(Of IEnumerable(Of String)))
also seems to work, as mentioned in comments by Ahmed Abdelhameed:
Dim csvRows = DirectCast({columns}, IEnumerable(Of IEnumerable(Of String))).Concat(rows) _
.Select(Function(r) String.Join(",", r))
Fixed fiddle #2 here.
Calling Enumerable.Concat(Of IEnumerable(Of String))
explicitly, without making use of inferencing, works also:
Dim csvRows = Enumerable.Concat(Of IEnumerable(Of String))({columns}, rows) _
.Select(Function(r) String.Join(",", r))
Fixed fiddle #3 here.
Thus your entire code should look like:
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)
solved How to resolve InvalidCastException after translating LINQ-to-JSON query from c# to VB.NET?