-1

I want to use the C# yield in VB.net 9 but it is not working.

private static IEnumerable<JToken> AllChildren(JToken json)
{
    foreach (var c in json.Children())
    {
        yield return c;
        foreach (var cc in AllChildren(c))
        {
            yield return cc;
        }
    }
}

this is the c# code and it is converted to VB.net using the online tools but it is not giving me the same result.

Private Shared Function AllChildren(json As JToken) As IEnumerable(Of JToken)
For Each c As var In json.Children()
    yield Return c
    For Each cc As var In AllChildren(c)
        yield Return cc
    Next
Next
End Function

Can anybody help me translate this?

Daniel Kelley
  • 7,579
  • 6
  • 42
  • 50
Cyanide
  • 17
  • 1
  • Hi The code you have in both C# and VB doesn't work properly. yield return will return control to the caller, so the for each will never be executed. See http://www.dotnetperls.com/yield for an example. You might like to rework your example. – Philip Johnson Dec 22 '15 at 10:53
  • To start with `var` is a C# keyword. The correct type would be `JToken` in this case. – Enigmativity Dec 22 '15 at 10:53
  • 2
    @PhilipJohnson - The C# code in the question is fine. – Enigmativity Dec 22 '15 at 10:54
  • 2
    What does "not working" entail? errors? invalid results? – Sayse Dec 22 '15 at 10:55
  • Yield is the keyword for an iterator. Why don't you simply google for "VB.NET Iterators", or check the [MSDN page](https://msdn.microsoft.com/en-us/library/dscyy5s0.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1) ? If you have a *specific* problem ("doesn't work" isn't specific) describe it and post *actual code* that displays the problem, what you expected and what you got. Also note that code-rewriting questions are out-of-scope for Stack Overflow. – Panagiotis Kanavos Dec 22 '15 at 11:00
  • @PhilipJohnson there's nothing wrong with the C# iterator. All lines will execute as long as the caller requests new items, eg in a `foreach` – Panagiotis Kanavos Dec 22 '15 at 11:01
  • 1
    Good point there is no logic error sorry! The VB code says For Each c AS var in. Should it not say For Each c In? – Philip Johnson Dec 22 '15 at 11:02
  • 1
    There is no Yield Return in VB. Only Yield. – shadow Dec 22 '15 at 11:18
  • Essentially a duplicate of http://stackoverflow.com/questions/97381/yield-in-vb-net? –  Dec 22 '15 at 12:05
  • 1
    VB 9 does not support Iterators. You need VB 11 (in Visual Studio 2012) or later to be able to use Iterators in VB. In VB, an Iterator Function needs the Iterator keyword in the declaration (`Private Shared Iterator Function .....`), and you use `Yield` rather than `Yield Return` to provide each value. – Blackwood Dec 22 '15 at 13:10
  • @NickDewitt not quite. The OP is asking about iterator syntax in VB.NET, not whether they exist – Panagiotis Kanavos Dec 22 '15 at 13:10
  • @Blackwood whose end of life comes in 3 weeks. The OP should familiarize himself with the target language rather than expecting tools to automagically write the code – Panagiotis Kanavos Dec 22 '15 at 13:13
  • @PanagiotisKanavos I agree that VB 9 is now very old and I would strongly recommend that the OP consider switching to the current version. However, the question clearly asks how to make the Iterator function work in VB 9. – Blackwood Dec 22 '15 at 13:16
  • @Blackwood impossible. This could be rewriten as a LINQ query though, although the requirement to return the parent followed by all its children will make this a bit tricky. In fact, one has to ask **why** the OP wants to *translate* already functioning code, instead of *calling* it – Panagiotis Kanavos Dec 22 '15 at 13:20
  • @PanagiotisKanavos It seems we are in agreement. – Blackwood Dec 22 '15 at 13:21
  • @PanagiotisKanavos maybe not a complete duplicate, but the (answer)[http://stackoverflow.com/a/382189/1641172] seems to cover all the points in this question. –  Dec 22 '15 at 13:30

2 Answers2

2

It took me a while to get it right, but this is what you need:

Private Shared Iterator Function AllChildren(json As JToken) As IEnumerable(Of JToken)
    For Each c As JToken In json.Children()
        Yield c
        For Each cc As JToken In AllChildren(c)
            Yield  cc
        Next
    Next
End Function

Since you are working in VB9 and you can't use iterators there is a very easy and neat option that you can use.

You just need to NuGet "Ix-Main" to get the Microsoft Reactive Framework team's "Interactive Extensions" - a bunch of handy IEnumerable<T> operators.

Then you can try this code:

Private Shared Function AllChildren2(json As JToken) As IEnumerable(Of JToken)
    Return EnumerableEx.Expand(json.Children(), Function (c) c.Children())
End Function
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
1

Create a C# class project, add json.net package/reference to the project. Add the following class

using Newtonsoft.Json.Linq;
using System.Collections.Generic;

namespace NewtonExtensions
{
    public static class Extensions
    {
        private static IEnumerable<JToken> AllChildren(JToken json)
        {
            foreach (var c in json.Children())
            {
                yield return c;
                foreach (var cc in AllChildren(c))
                {
                    yield return cc;
                }
            }
        }
    }
}

Compile the above project. In the current project, add a reference to the project above. Where the extension method is to be used, add a using statement.

Underlying thing here is unless using an older Express version of Visual Studio we can easily share code between languages.

EDIT Here is the same as above as an extension method

using Newtonsoft.Json.Linq; using System.Collections.Generic;

namespace NewtonExtensions
{
    public static class Extensions
    {
        public static IEnumerable<JToken> AllChildren(this JToken json)
        {
            foreach (var c in json.Children())
            {
                yield return c;
                foreach (var cc in AllChildren(c))
                {
                    yield return cc;
                }
            }
        }
    }
}

Example usage in vb.net where I use xml literal for the json string. You would read in the json as normally would say from a file etc.

The Imports NewtonExtensions is in a C# class project with a namespace of NewtonExtensions.

I show two methods to iterate data after using the language extension method.

Imports NewtonExtensions
Imports Newtonsoft.Json.Linq

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) _
        Handles Button1.Click

        Dim jsonString As String =
            <json>
{
    "ADDRESS_MAP":{

        "ADDRESS_LOCATION":{
            "type":"separator",
            "name":"Address",
            "value":"",
            "FieldID":40
        },
        "LOCATION":{
            "type":"locations",
            "name":"Location",
            "keyword":{
                "1":"LOCATION1"
            },
            "value":{
                "1":"United States"
            },
            "FieldID":41
        },
        "FLOOR_NUMBER":{
            "type":"number",
            "name":"Floor Number",
            "value":"0",
            "FieldID":55
        },
        "self":{
            "id":"2",
            "name":"Address Map"
        }
    }
}                
            </json>.Value


        Dim results As JObject = JObject.Parse(jsonString)

        Console.WriteLine("Example 1")
        For Each item As KeyValuePair(Of String, JToken) In results
            Console.WriteLine(item.Key)
            Dim test = item.Value.AllChildren
            For Each subItem In test
                Console.WriteLine(subItem)
                Console.WriteLine()
            Next
        Next
        Console.WriteLine(New String("-"c, 50))
        Console.WriteLine("Example 2")
        results.Cast(Of KeyValuePair(Of String, JToken)) _
            .ToList.ForEach(
                Sub(v)
                    Console.WriteLine(v.Key)
                    Console.WriteLine(v.Value)
                End Sub)


    End Sub
End Class
Karen Payne
  • 4,341
  • 2
  • 14
  • 31
  • This isn't a bad solution, but you're 90% of the way there to making it an extension method. Why not add the `this`? – Enigmativity Dec 22 '15 at 23:30