CodeConverter
CodeConverter copied to clipboard
VB -> C#: Query syntax -Linq with multiple groups
Input code
Public Class Class1
Sub Foo()
Dim xs As New List(Of String)
Dim y = From x In xs Group By x.Length, x.Count() Into Group
End Sub
End Class
Erroneous output
public class Class1
{
public void Foo()
{
List<string> xs = new List<string>();
;/* Cannot convert LocalDeclarationStatementSyntax, System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at ICSharpCode.CodeConverter.CSharp.QueryConverter.ConvertSubQuery(FromClauseSyntax fromClauseSyntax, QueryClauseSyntax clauseEnd, QueryBodySyntax nestedClause, SyntaxList`1 convertedClauses)
at ICSharpCode.CodeConverter.CSharp.QueryConverter.ConvertQuerySegments(IEnumerable`1 querySegments, FromClauseSyntax fromClauseSyntax)
at ICSharpCode.CodeConverter.CSharp.QueryConverter.ConvertClauses(SyntaxList`1 clauses)
at ICSharpCode.CodeConverter.CSharp.VisualBasicConverter.NodesVisitor.VisitQueryExpression(QueryExpressionSyntax node)
at Microsoft.CodeAnalysis.VisualBasic.Syntax.QueryExpressionSyntax.Accept[TResult](VisualBasicSyntaxVisitor`1 visitor)
at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxVisitor`1.Visit(SyntaxNode node)
at ICSharpCode.CodeConverter.CSharp.CommentConvertingNodesVisitor.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxVisitor`1.VisitQueryExpression(QueryExpressionSyntax node)
at Microsoft.CodeAnalysis.VisualBasic.Syntax.QueryExpressionSyntax.Accept[TResult](VisualBasicSyntaxVisitor`1 visitor)
at ICSharpCode.CodeConverter.CSharp.CommonConversions.ConvertInitializer(VariableDeclaratorSyntax declarator)
at ICSharpCode.CodeConverter.CSharp.CommonConversions.SplitVariableDeclarations(VariableDeclaratorSyntax declarator, Boolean preferExplicitType)
at ICSharpCode.CodeConverter.CSharp.VisualBasicConverter.MethodBodyVisitor.VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
at Microsoft.CodeAnalysis.VisualBasic.Syntax.LocalDeclarationStatementSyntax.Accept[TResult](VisualBasicSyntaxVisitor`1 visitor)
at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxVisitor`1.Visit(SyntaxNode node)
at ICSharpCode.CodeConverter.CSharp.CommentConvertingMethodBodyVisitor.ConvertWithTrivia(SyntaxNode node)
at ICSharpCode.CodeConverter.CSharp.CommentConvertingMethodBodyVisitor.DefaultVisit(SyntaxNode node)
Input:
Dim y = From x In xs Group By x.Length, x.Count() Into Group
*/
}
}
Expected output
public class Class1
{
public void Foo()
{
List<string> xs = new List<string>();
// Not 100% that this does the same thing.
var y = from x in xs group x by new { x.Length, Count = x.Count(), Group = xs.AsEnumerable() };
}
}
I'll leave this open for now since its much more specific and achievable than #29 I'd slightly caution against working on this issue in isolation though. There's a collection of very custom code for the query syntax, but really, more careful investigation into how the vb and c# parser deal with it might yield a more general solution. The main problem I've had, is that I don't understand VB's query syntax. It's a whole language of its own that appears more expressive than C#s version. If we can find a way to turn it into linq method chaining in vb, then convert that, it'd be easier. Either the compiler, or some other library may assist. Checking what sort of il gets generated would be good start
I've stopped this throwing an error, but not gone as far as completely fixing it (it'll still be a compile error from the consuming code). The output of the LinqGroupByTwoThingsAnonymously
test is now:
using System.Collections.Generic;
using System.Linq;
public partial class Class1
{
public void Foo()
{
var xs = new List<string>();
var y = from x in xs
group x by new { x.Length, Count = x.Count() };
}
}
but I think should be
using System.Collections.Generic;
using System.Linq;
public partial class Class1
{
public void Foo()
{
var xs = new List<string>();
var y = from x in xs
group x by new { x.Length, Count = x.Count() } into g
select new { Length = g.Key.Length, Count = g.Key.Count, Group = g.AsEnumerable() };
}
}
Exact opposite error message (no elements versus more than one), but it might be related.
Cannot convert QueryExpressionSyntax, System.InvalidOperationException: Sequence contains more than one element
at System.Linq.Enumerable.Single[TSource](IEnumerable1 source) at ICSharpCode.CodeConverter.CSharp.QueryConverter.<ConvertSubQueryAsync>d__15.MoveNext() --- End of stack trace from previous location where exception was thrown --- at ICSharpCode.CodeConverter.CSharp.QueryConverter.<ConvertQueryWithContinuationAsync>d__14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at ICSharpCode.CodeConverter.CSharp.QueryConverter.<ConvertQueryWithContinuationsAsync>d__13.MoveNext() --- End of stack trace from previous location where exception was thrown --- at ICSharpCode.CodeConverter.CSharp.QueryConverter.<ConvertQuerySegmentsAsync>d__11.MoveNext() --- End of stack trace from previous location where exception was thrown --- at ICSharpCode.CodeConverter.CSharp.QueryConverter.<ConvertClausesAsync>d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at ICSharpCode.CodeConverter.CSharp.ExpressionNodeVisitor.<VisitQueryExpression>d__70.MoveNext() --- End of stack trace from previous location where exception was thrown --- at ICSharpCode.CodeConverter.CSharp.CommentConvertingVisitorWrapper.<ConvertHandledAsync>d__8
1.MoveNext()
Dim gridDataSource = (From p In _Parent Join pt In _ParentType On pt.parentId Equals p.parentId Group p By key = p.parentId, desc = p.ParentTypeDesc, sequence = pt.Sequence Into Group Select New With {.parentId = key, .ParentTypeDesc = desc, .Sequence = sequence}).OrderBy(Function(c) c.Sequence)