提交 8732a4ed 编写于 作者: M Manish Vasani

Address PR feedback

上级 491af6ab
...@@ -3958,5 +3958,99 @@ static void Main() ...@@ -3958,5 +3958,99 @@ static void Main()
VerifyOperationTreeAndDiagnosticsForTest<QueryExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics); VerifyOperationTreeAndDiagnosticsForTest<QueryExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
} }
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(17838, "https://github.com/dotnet/roslyn/issues/17838")]
public void IOperationForQueryClause()
{
string source = @"
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>() { 1, 2, 3, 4, 5, 6, 7 };
var r = from i in c /*<bind>*/select i + 1/*</bind>*/;
}
}
";
string expectedOperationTree = @"
IInvocationExpression (System.Collections.Generic.IEnumerable<System.Int32> System.Linq.Enumerable.Select<System.Int32, System.Int32>(this System.Collections.Generic.IEnumerable<System.Int32> source, System.Func<System.Int32, System.Int32> selector)) (OperationKind.InvocationExpression, Type: System.Collections.Generic.IEnumerable<System.Int32>) (Syntax: 'select i + 1')
Instance Receiver: null
Arguments(2):
IArgument (ArgumentKind.Explicit, Matching Parameter: source) (OperationKind.Argument) (Syntax: 'from i in c')
IConversionExpression (Implicit, TryCast: False, Unchecked) (OperationKind.ConversionExpression, Type: System.Collections.Generic.IEnumerable<System.Int32>) (Syntax: 'from i in c')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
Operand: ILocalReferenceExpression: c (OperationKind.LocalReferenceExpression, Type: System.Collections.Generic.List<System.Int32>) (Syntax: 'c')
InConversion: null
OutConversion: null
IArgument (ArgumentKind.Explicit, Matching Parameter: selector) (OperationKind.Argument) (Syntax: 'i + 1')
IConversionExpression (Implicit, TryCast: False, Unchecked) (OperationKind.ConversionExpression, Type: System.Func<System.Int32, System.Int32>) (Syntax: 'i + 1')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand: IAnonymousFunctionExpression (Symbol: lambda expression) (OperationKind.AnonymousFunctionExpression, Type: null) (Syntax: 'i + 1')
IBlockStatement (1 statements) (OperationKind.BlockStatement) (Syntax: 'i + 1')
IReturnStatement (OperationKind.ReturnStatement) (Syntax: 'i + 1')
ReturnedValue: IBinaryOperatorExpression (BinaryOperatorKind.Add) (OperationKind.BinaryOperatorExpression, Type: System.Int32) (Syntax: 'i + 1')
Left: IOperation: (OperationKind.None) (Syntax: 'i')
Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
InConversion: null
OutConversion: null
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<SelectClauseSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(17838, "https://github.com/dotnet/roslyn/issues/17838")]
public void IOperationForRangeVariableDefinition()
{
string source = @"
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>() { 1, 2, 3, 4, 5, 6, 7 };
var r = /*<bind>*/from i in c/*</bind>*/ select i + 1;
}
}
";
string expectedOperationTree = @"
ILocalReferenceExpression: c (OperationKind.LocalReferenceExpression, Type: System.Collections.Generic.List<System.Int32>) (Syntax: 'c')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<FromClauseSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(17838, "https://github.com/dotnet/roslyn/issues/17838")]
public void IOperationForRangeVariableReference()
{
string source = @"
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>() { 1, 2, 3, 4, 5, 6, 7 };
var r = from i in c select /*<bind>*/i/*</bind>*/ + 1;
}
}
";
string expectedOperationTree = @"
IOperation: (OperationKind.None) (Syntax: 'i')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<IdentifierNameSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
} }
} }
...@@ -5617,8 +5617,11 @@ internal sealed partial class LazyCollectionElementInitializerExpression : BaseC ...@@ -5617,8 +5617,11 @@ internal sealed partial class LazyCollectionElementInitializerExpression : BaseC
/// <summary> /// <summary>
/// Represents an unrolled/lowered query expression in C# and VB. /// Represents an unrolled/lowered query expression in C# and VB.
/// For example, for the query expression "from x in set where x.Name != null select x.Name", the select clause is the last clause of the unrolled query expression, /// For example, for the query expression "from x in set where x.Name != null select x.Name", the Operation tree has the following shape:
/// with the where clause as one of its descendant, and the from clause as the descendant of the where clause. /// ITranslatedQueryExpression
/// IInvocationExpression ('Select' invocation for "select x.Name")
/// IInvocationExpression ('Where' invocation for "where x.Name != null")
/// IInvocationExpression ('From' invocation for "from x in set")
/// </summary> /// </summary>
internal abstract partial class BaseTranslatedQueryExpression : Operation, ITranslatedQueryExpression internal abstract partial class BaseTranslatedQueryExpression : Operation, ITranslatedQueryExpression
{ {
...@@ -5650,8 +5653,11 @@ public override void Accept(OperationVisitor visitor) ...@@ -5650,8 +5653,11 @@ public override void Accept(OperationVisitor visitor)
/// <summary> /// <summary>
/// Represents an unrolled/lowered query expression in C# and VB. /// Represents an unrolled/lowered query expression in C# and VB.
/// For example, for the query expression "from x in set where x.Name != null select x.Name", the select clause is the last clause of the unrolled query expression, /// For example, for the query expression "from x in set where x.Name != null select x.Name", the Operation tree has the following shape:
/// with the where clause as one of its descendant, and the from clause as the descendant of the where clause. /// ITranslatedQueryExpression
/// IInvocationExpression ('Select' invocation for "select x.Name")
/// IInvocationExpression ('Where' invocation for "where x.Name != null")
/// IInvocationExpression ('From' invocation for "from x in set")
/// </summary> /// </summary>
internal sealed partial class TranslatedQueryExpression : BaseTranslatedQueryExpression, ITranslatedQueryExpression internal sealed partial class TranslatedQueryExpression : BaseTranslatedQueryExpression, ITranslatedQueryExpression
{ {
...@@ -5665,8 +5671,11 @@ internal sealed partial class TranslatedQueryExpression : BaseTranslatedQueryExp ...@@ -5665,8 +5671,11 @@ internal sealed partial class TranslatedQueryExpression : BaseTranslatedQueryExp
/// <summary> /// <summary>
/// Represents an unrolled/lowered query expression in C# and VB. /// Represents an unrolled/lowered query expression in C# and VB.
/// For example, for the query expression "from x in set where x.Name != null select x.Name", the select clause is the last clause of the unrolled query expression, /// For example, for the query expression "from x in set where x.Name != null select x.Name", the Operation tree has the following shape:
/// with the where clause as one of its descendant, and the from clause as the descendant of the where clause. /// ITranslatedQueryExpression
/// IInvocationExpression ('Select' invocation for "select x.Name")
/// IInvocationExpression ('Where' invocation for "where x.Name != null")
/// IInvocationExpression ('From' invocation for "from x in set")
/// </summary> /// </summary>
internal sealed partial class LazyTranslatedQueryExpression : BaseTranslatedQueryExpression, ITranslatedQueryExpression internal sealed partial class LazyTranslatedQueryExpression : BaseTranslatedQueryExpression, ITranslatedQueryExpression
{ {
......
...@@ -4,8 +4,11 @@ namespace Microsoft.CodeAnalysis.Semantics ...@@ -4,8 +4,11 @@ namespace Microsoft.CodeAnalysis.Semantics
{ {
/// <summary> /// <summary>
/// Represents an unrolled/lowered query expression in C# and VB. /// Represents an unrolled/lowered query expression in C# and VB.
/// For example, for the query expression "from x in set where x.Name != null select x.Name", the select clause is the last clause of the unrolled query expression, /// For example, for the query expression "from x in set where x.Name != null select x.Name", the Operation tree has the following shape:
/// with the where clause as one of its descendant, and the from clause as the descendant of the where clause. /// ITranslatedQueryExpression
/// IInvocationExpression ('Select' invocation for "select x.Name")
/// IInvocationExpression ('Where' invocation for "where x.Name != null")
/// IInvocationExpression ('From' invocation for "from x in set")
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This interface is reserved for implementation by its associated APIs. We reserve the right to /// This interface is reserved for implementation by its associated APIs. We reserve the right to
......
...@@ -49,7 +49,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -49,7 +49,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
_instrumentTopLevelNonCompilerGeneratedExpressionsInQuery = Not instrumentQueryLambdaBody _instrumentTopLevelNonCompilerGeneratedExpressionsInQuery = Not instrumentQueryLambdaBody
Dim returnstmt = RewriteQueryLambdaBody(AddressOf VisitExpressionNode, node, _rangeVariableMap, _instrumenterOpt, instrumentQueryLambdaBody:=instrumentQueryLambdaBody AndAlso Instrument) Dim rewrittenBody As BoundExpression = VisitExpressionNode(node.Expression)
Dim returnstmt = CreateReturnStatementForQueryLambdaBody(rewrittenBody, node)
If instrumentQueryLambdaBody AndAlso Instrument Then
returnstmt = _instrumenterOpt.InstrumentQueryLambdaBody(node, returnstmt)
End If
RemoveRangeVariables(node, _rangeVariableMap)
_instrumentTopLevelNonCompilerGeneratedExpressionsInQuery = save_createSequencePointsForTopLevelNonCompilerGeneratedExpressions _instrumentTopLevelNonCompilerGeneratedExpressionsInQuery = save_createSequencePointsForTopLevelNonCompilerGeneratedExpressions
...@@ -90,14 +97,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -90,14 +97,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim paramRef As New BoundParameter(node.Syntax, Dim paramRef As New BoundParameter(node.Syntax,
parameter, parameter,
False, False,
parameter.Type, parameter.Type)
hasErrors:=parameter.Type.IsErrorType())
If Not paramRef.HasErrors AndAlso isReservedName AndAlso Not String.Equals(parameterName, StringConstants.Group, StringComparison.Ordinal) Then If isReservedName AndAlso Not String.Equals(parameterName, StringConstants.Group, StringComparison.Ordinal) Then
If parameter.Type.IsErrorType() Then
' Skip adding to the range variable map for error case.
firstUnmappedRangeVariable += 1
Else
' Compound variable. ' Compound variable.
' Each range variable is an Anonymous Type property. ' Each range variable is an Anonymous Type property.
Debug.Assert(parameterName.Equals(StringConstants.It) OrElse parameterName.Equals(StringConstants.It1) OrElse parameterName.Equals(StringConstants.It2)) Debug.Assert(parameterName.Equals(StringConstants.It) OrElse parameterName.Equals(StringConstants.It1) OrElse parameterName.Equals(StringConstants.It2))
PopulateRangeVariableMapForAnonymousType(node.Syntax, paramRef, nodeRangeVariables, firstUnmappedRangeVariable, rangeVariableMap, inExpressionLambda) PopulateRangeVariableMapForAnonymousType(node.Syntax, paramRef, nodeRangeVariables, firstUnmappedRangeVariable, rangeVariableMap, inExpressionLambda)
End If
Else Else
' Simple case, range variable is a lambda parameter. ' Simple case, range variable is a lambda parameter.
Debug.Assert(IdentifierComparison.Equals(parameterName, nodeRangeVariables(firstUnmappedRangeVariable).Name)) Debug.Assert(IdentifierComparison.Equals(parameterName, nodeRangeVariables(firstUnmappedRangeVariable).Name))
...@@ -158,28 +169,21 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -158,28 +169,21 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Next Next
End Sub End Sub
Friend Shared Function RewriteQueryLambdaBody( Friend Shared Function CreateReturnStatementForQueryLambdaBody(
expressionRewriter As Func(Of BoundExpression, BoundExpression), rewrittenBody As BoundExpression,
originalNode As BoundQueryLambda, originalNode As BoundQueryLambda) As BoundStatement
rangeVariableMap As Dictionary(Of RangeVariableSymbol, BoundExpression),
Optional instrumenterOpt As Instrumenter = Nothing,
Optional instrumentQueryLambdaBody As Boolean = False) As BoundStatement
Dim returnstmt As BoundStatement = New BoundReturnStatement(originalNode.Syntax, Return New BoundReturnStatement(originalNode.Syntax,
expressionRewriter(originalNode.Expression), rewrittenBody,
Nothing, Nothing,
Nothing) Nothing)
End Function
If instrumentQueryLambdaBody Then Friend Shared Sub RemoveRangeVariables(originalNode As BoundQueryLambda, rangeVariableMap As Dictionary(Of RangeVariableSymbol, BoundExpression))
returnstmt = instrumenterOpt.InstrumentQueryLambdaBody(originalNode, returnstmt)
End If
For Each rangeVar As RangeVariableSymbol In originalNode.RangeVariables For Each rangeVar As RangeVariableSymbol In originalNode.RangeVariables
rangeVariableMap.Remove(rangeVar) rangeVariableMap.Remove(rangeVar)
Next Next
End Sub
Return returnstmt
End Function
Friend Shared Function RewriteQueryLambda(rewrittenBody As BoundStatement, originalNode As BoundQueryLambda) As BoundLambda Friend Shared Function RewriteQueryLambda(rewrittenBody As BoundStatement, originalNode As BoundQueryLambda) As BoundLambda
Dim lambdaBody = New BoundBlock(originalNode.Syntax, Dim lambdaBody = New BoundBlock(originalNode.Syntax,
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.BoundTreeVisitor
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Namespace Microsoft.CodeAnalysis.Semantics Namespace Microsoft.CodeAnalysis.Semantics
...@@ -9,11 +10,17 @@ Namespace Microsoft.CodeAnalysis.Semantics ...@@ -9,11 +10,17 @@ Namespace Microsoft.CodeAnalysis.Semantics
' We rewrite query lambda into regular lambda with 2 passes. ' We rewrite query lambda into regular lambda with 2 passes.
' Pass 1 uses helper methods from LocalRewriter to do the lowering. This introduces large number of DAGs. ' Pass 1 uses helper methods from LocalRewriter to do the lowering. This introduces large number of DAGs.
' Pass 2 walks over the lowered tree and replaces duplicate bound nodes in the tree with their clones - this is a requirement for the Operation tree. ' Pass 2 walks over the lowered tree and replaces duplicate bound nodes in the tree with their clones - this is a requirement for the Operation tree.
' Note that the rewriter also rewrites all the query lambdas inside the body of this query lambda.
Try
Dim pass1Rewriter As New QueryLambdaRewriterPass1 Dim pass1Rewriter As New QueryLambdaRewriterPass1
Dim rewrittenLambda As BoundLambda = DirectCast(pass1Rewriter.VisitQueryLambda(node), BoundLambda) Dim rewrittenLambda As BoundLambda = DirectCast(pass1Rewriter.VisitQueryLambda(node), BoundLambda)
Dim pass2Rewriter As New QueryLambdaRewriterPass2 Dim pass2Rewriter As New QueryLambdaRewriterPass2
Return pass2Rewriter.VisitLambda(rewrittenLambda) Return pass2Rewriter.VisitLambda(rewrittenLambda)
Catch ex As CancelledByStackGuardException
Return node
End Try
End Function End Function
Private NotInheritable Class QueryLambdaRewriterPass1 Private NotInheritable Class QueryLambdaRewriterPass1
...@@ -25,9 +32,11 @@ Namespace Microsoft.CodeAnalysis.Semantics ...@@ -25,9 +32,11 @@ Namespace Microsoft.CodeAnalysis.Semantics
End Sub End Sub
Public Overrides Function VisitQueryLambda(node As BoundQueryLambda) As BoundNode Public Overrides Function VisitQueryLambda(node As BoundQueryLambda) As BoundNode
LocalRewriter.PopulateRangeVariableMapForQueryLambdaRewrite(node, _rangeVariableMap, inExpressionLambda:=False) LocalRewriter.PopulateRangeVariableMapForQueryLambdaRewrite(node, _rangeVariableMap, inExpressionLambda:=True)
Dim rewrittenBody As BoundStatement = LocalRewriter.RewriteQueryLambdaBody(AddressOf VisitExpressionWithStackGuard, node, _rangeVariableMap) Dim rewrittenBody As BoundExpression = VisitExpressionWithStackGuard(node.Expression)
Return LocalRewriter.RewriteQueryLambda(rewrittenBody, node) Dim rewrittenStatement As BoundStatement = LocalRewriter.CreateReturnStatementForQueryLambdaBody(rewrittenBody, node)
LocalRewriter.RemoveRangeVariables(node, _rangeVariableMap)
Return LocalRewriter.RewriteQueryLambda(rewrittenStatement, node)
End Function End Function
Public Overrides Function VisitRangeVariable(node As BoundRangeVariable) As BoundNode Public Overrides Function VisitRangeVariable(node As BoundRangeVariable) As BoundNode
...@@ -39,13 +48,12 @@ Namespace Microsoft.CodeAnalysis.Semantics ...@@ -39,13 +48,12 @@ Namespace Microsoft.CodeAnalysis.Semantics
End If End If
#If DEBUG Then #If DEBUG Then
' Range variable reference should be rewritten to a parameter reference, or a call or a property access. ' Range variable reference should be rewritten to a parameter reference or a property access.
' We clone these bound nodes in QueryLambdaRewriterPass2 to avoid dag in the generated bound tree. ' We clone these bound nodes in QueryLambdaRewriterPass2 to avoid dag in the generated bound tree.
' If the LocalRewriter is changed to generate more kind of bound nodes for range variables, we should handle these in QueryLambdaRewriterPass2. ' If the LocalRewriter is changed to generate more kind of bound nodes for range variables, we should handle these in QueryLambdaRewriterPass2.
' Below assert helps us to stay in sync with the LocalRewriter. ' Below assert helps us to stay in sync with the LocalRewriter.
Select Case expression.Kind Select Case expression.Kind
Case BoundKind.Parameter Case BoundKind.Parameter
Case BoundKind.Call
Case BoundKind.PropertyAccess Case BoundKind.PropertyAccess
Exit Select Exit Select
Case Else Case Else
...@@ -59,34 +67,16 @@ Namespace Microsoft.CodeAnalysis.Semantics ...@@ -59,34 +67,16 @@ Namespace Microsoft.CodeAnalysis.Semantics
Private NotInheritable Class QueryLambdaRewriterPass2 Private NotInheritable Class QueryLambdaRewriterPass2
Inherits BoundTreeRewriterWithStackGuard Inherits BoundTreeRewriterWithStackGuard
Private ReadOnly _uniqueNodes As HashSet(Of BoundExpression) Private ReadOnly _uniqueNodes As New HashSet(Of BoundParameter)
Public Sub New()
_uniqueNodes = New HashSet(Of BoundExpression)
End Sub
Private Function HandleNode(Of T As BoundExpression)(node As T, cloneNode As Func(Of T, T)) As T
If Not _uniqueNodes.Add(node) Then
node = cloneNode(node)
_uniqueNodes.Add(node)
End If
Return node
End Function
Public Overrides Function VisitParameter(node As BoundParameter) As BoundNode Public Overrides Function VisitParameter(node As BoundParameter) As BoundNode
node = DirectCast(MyBase.VisitParameter(node), BoundParameter) node = DirectCast(MyBase.VisitParameter(node), BoundParameter)
Return HandleNode(node, cloneNode:=Function(n) New BoundParameter(node.Syntax, node.ParameterSymbol, node.IsLValue, node.SuppressVirtualCalls, node.Type, node.HasErrors))
End Function
Public Overrides Function VisitCall(node As BoundCall) As BoundNode If node.ParameterSymbol?.ContainingSymbol.IsQueryLambdaMethod AndAlso Not _uniqueNodes.Add(node) Then
node = DirectCast(MyBase.VisitCall(node), BoundCall) node = New BoundParameter(node.Syntax, node.ParameterSymbol, node.IsLValue, node.SuppressVirtualCalls, node.Type, node.HasErrors)
Return HandleNode(node, cloneNode:=Function(n) New BoundCall(node.Syntax, node.Method, node.MethodGroupOpt, node.ReceiverOpt, node.Arguments, node.ConstantValueOpt, node.IsLValue, node.SuppressObjectClone, node.Type, node.HasErrors)) End If
End Function
Public Overrides Function VisitPropertyAccess(node As BoundPropertyAccess) As BoundNode Return node
node = DirectCast(MyBase.VisitPropertyAccess(node), BoundPropertyAccess)
Return HandleNode(node, cloneNode:=Function(n) New BoundPropertyAccess(node.Syntax, node.PropertySymbol, node.PropertyGroupOpt, node.AccessKind, node.IsWriteable, node.IsLValue, node.ReceiverOpt, node.Arguments, node.Type, node.HasErrors))
End Function End Function
End Class End Class
End Class End Class
......
...@@ -238,12 +238,10 @@ ITranslatedQueryExpression (OperationKind.TranslatedQueryExpression, Type: Syste ...@@ -238,12 +238,10 @@ ITranslatedQueryExpression (OperationKind.TranslatedQueryExpression, Type: Syste
IReturnStatement (OperationKind.ReturnStatement) (Syntax: 'Group By w ... nto Count()') IReturnStatement (OperationKind.ReturnStatement) (Syntax: 'Group By w ... nto Count()')
ReturnedValue: IAnonymousObjectCreationExpression (OperationKind.AnonymousObjectCreationExpression, Type: <anonymous type: Key w As System.String(), Key z As System.String, Key Count As System.Int32>) (Syntax: 'Group By w ... nto Count()') ReturnedValue: IAnonymousObjectCreationExpression (OperationKind.AnonymousObjectCreationExpression, Type: <anonymous type: Key w As System.String(), Key z As System.String, Key Count As System.Int32>) (Syntax: 'Group By w ... nto Count()')
Initializers(3): Initializers(3):
IInvocationExpression ( Function <anonymous type: Key w As System.String(), Key z As System.String>.get_w() As System.String()) (OperationKind.InvocationExpression, Type: System.String()) (Syntax: 'Group By w ... nto Count()') IPropertyReferenceExpression: ReadOnly Property <anonymous type: Key w As System.String(), Key z As System.String>.w As System.String() (OperationKind.PropertyReferenceExpression, Type: System.String()) (Syntax: 'Group By w ... nto Count()')
Instance Receiver: IParameterReferenceExpression: $VB$It (OperationKind.ParameterReferenceExpression, Type: <anonymous type: Key w As System.String(), Key z As System.String>) (Syntax: 'Group By w ... nto Count()') Instance Receiver: IParameterReferenceExpression: $VB$It (OperationKind.ParameterReferenceExpression, Type: <anonymous type: Key w As System.String(), Key z As System.String>) (Syntax: 'Group By w ... nto Count()')
Arguments(0) IPropertyReferenceExpression: ReadOnly Property <anonymous type: Key w As System.String(), Key z As System.String>.z As System.String (OperationKind.PropertyReferenceExpression, Type: System.String) (Syntax: 'Group By w ... nto Count()')
IInvocationExpression ( Function <anonymous type: Key w As System.String(), Key z As System.String>.get_z() As System.String) (OperationKind.InvocationExpression, Type: System.String) (Syntax: 'Group By w ... nto Count()')
Instance Receiver: IParameterReferenceExpression: $VB$It (OperationKind.ParameterReferenceExpression, Type: <anonymous type: Key w As System.String(), Key z As System.String>) (Syntax: 'Group By w ... nto Count()') Instance Receiver: IParameterReferenceExpression: $VB$It (OperationKind.ParameterReferenceExpression, Type: <anonymous type: Key w As System.String(), Key z As System.String>) (Syntax: 'Group By w ... nto Count()')
Arguments(0)
IInvocationExpression ( Function System.Collections.Generic.IEnumerable(Of System.String).Count() As System.Int32) (OperationKind.InvocationExpression, Type: System.Int32) (Syntax: 'Count()') IInvocationExpression ( Function System.Collections.Generic.IEnumerable(Of System.String).Count() As System.Int32) (OperationKind.InvocationExpression, Type: System.Int32) (Syntax: 'Count()')
Instance Receiver: IParameterReferenceExpression: $VB$ItAnonymous (OperationKind.ParameterReferenceExpression, Type: System.Collections.Generic.IEnumerable(Of System.String)) (Syntax: 'Group By w ... nto Count()') Instance Receiver: IParameterReferenceExpression: $VB$ItAnonymous (OperationKind.ParameterReferenceExpression, Type: System.Collections.Generic.IEnumerable(Of System.String)) (Syntax: 'Group By w ... nto Count()')
Arguments(0) Arguments(0)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册