Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Translation of c# linq to vb - overload resolution failure in intellisense with 'selectmany' statement

I've tried every translation service under the sun to get this syntax right but I still get "Overload resolution failed because no accessible 'SelectMany' can be called with these arguments" on the first part of the select statement (up to the full stop just before the groupby keyword)

the original c# statement from an online example I'm trying to get working locally:

public IEnumerable<TagGroup> GetTagGroups()
{

    var tagGroups = 
        // extract the delimited tags string and session id from all sessions
        DbSet.Select(s => new { s.Tags, s.Id })
            .ToArray() // we'll process them in memory.

            // split the "Tags" string into individual tags 
            // and flatten into {tag, id} pairs
            .SelectMany(
                s =>
                s.Tags.Split(_tagDelimiter, StringSplitOptions.RemoveEmptyEntries)
                    .Select(t => new { Tag = t, s.Id })
            )

            // group {tag, id} by tag into unique {tag, [session-id-array]}
            .GroupBy(g => g.Tag, data => data.Id)

            // project the group into TagGroup instances
            // ensuring that ids array in each array are unique
            .Select(tg => new TagGroup 
                            {
                                Tag = tg.Key, 
                                Ids = tg.Distinct().ToArray(),
                            })
            .OrderBy(tg => tg.Tag);

    return tagGroups;
}

The closest I've come to it in VB:

Public Function GetTagGroups() As IEnumerable(Of TagGroup)

    ' extract the delimited tags string and session id from all sessions
    ' we'll process them in memory.
    ' split the "Tags" string into individual tags 
    ' and flatten into {tag, id} pairs

    ' group {tag, id} by tag into unique {tag, [session-id-array]}

    ' project the group into TagGroup instances
    ' ensuring that ids array in each array are unique

    Dim tagGroups = DbSet.[Select](Function(s) New With { _
        s.Tags, _
        s.Id _
    }).ToArray().SelectMany(Function(s) s.Tags.Split(_tagDelimiter, StringSplitOptions.RemoveEmptyEntries).[Select](Function(t) New With { _
        Key .Tag = t, _
        s.Id _
    })).GroupBy(Function(g) g.Tag, Function(data) data.Id).[Select](Function(tg) New With { _
        Key .Tag = tg.Key, _
        Key .Ids = tg.Distinct().ToArray() _
    }).OrderBy(Function(tg) tg.Tag)

    Return tagGroups
End Function

This results in the visual studio 2012 intellisense underlining in blue the first part of the statement from "DbSet" on the first line through to the last parenthesis before the ".GroupBy" near the bottom. The error is "Overload resolution failed because no accessible 'SelectMany' can be called with these arguments".

As it's a code example I'm trying to convert to vb to run locally and understand and I'm not experienced enough with linq I'm completely at a loss of how to try and deal with this. It's way beyond my current understanding so could be a simple syntax error or a complete hash from start to finish for all I know!

Would be very grateful for any pointers.

like image 339
TheMook Avatar asked Sep 02 '25 05:09

TheMook


1 Answers

I have now put this in VS2k8, and as well as the two simple issues with the VB sample I previously noted:

  • The first two New With constructs must specify .<field> = AFAIK, and
  • the last New With should not be anonymous.

I now also note these are the declarations I needed to get the code to not have errors. Other than adding intermediate query variables (which BTW mean you could thread the C# comments back in), I don't recall actually changing the code further. Note the _tagDelimiter as a Char() -- what did the C# code declare it as? (Looking at the String.Split overloads that mention StringSplitOptions it has to be Char() or String() or C# is implicitly changing types somewhere that VB.NET doesn't.)

Class TagList
    Public Tags As String
    Public Id As String
End Class

Private DbSet As IQueryable(Of TagList)

Class TagGroup
    Public Tag As String
    Public Ids() As String
End Class

Private _tagDelimiter As Char()

Public Function GetTagGroups() As IEnumerable(Of TagGroup)

    Dim theTags = DbSet.[Select](Function(s) New With { _
        .Tags = s.Tags, _
        .Id = s.Id _
    }).ToArray()

    Dim many = theTags.SelectMany(Function(s) s.Tags.Split(_tagDelimiter, StringSplitOptions.RemoveEmptyEntries).[Select](Function(t) New With { _
        Key .Tag = t, _
        .Id = s.Id _
    }))

    Dim grouped = many.GroupBy(Function(g) g.Tag, Function(data) data.Id)

    Dim unordered = grouped.[Select](Function(tg) New TagGroup With { _
        .Tag = tg.Key, _
        .Ids = tg.Distinct().ToArray() _
    })
    Dim tagGroups = unordered.OrderBy(Function(tg) tg.Tag)

    Return tagGroups
End Function
like image 50
Mark Hurd Avatar answered Sep 04 '25 23:09

Mark Hurd