/// <summary> /// Generates switch cases for the provided grain type. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="methodIdArgument"> /// The method id argument, which is used to select the correct switch label. /// </param> /// <param name="generateMethodHandler"> /// The function used to generate switch block statements for each method. /// </param> /// <returns> /// The switch cases for the provided grain type. /// </returns> public static SwitchSectionSyntax[] GenerateGrainInterfaceAndMethodSwitch( Type grainType, IdentifierNameSyntax methodIdArgument, Func <MethodInfo, StatementSyntax[]> generateMethodHandler) { var interfaces = GrainInterfaceData.GetRemoteInterfaces(grainType); interfaces[GrainInterfaceData.GetGrainInterfaceId(grainType)] = grainType; // Switch on interface id. var interfaceCases = new List <SwitchSectionSyntax>(); foreach (var @interface in interfaces) { var interfaceType = @interface.Value; var interfaceId = @interface.Key; var methods = GrainInterfaceData.GetMethods(interfaceType); var methodCases = new List <SwitchSectionSyntax>(); // Switch on method id. foreach (var method in methods) { // Generate switch case. var methodId = GrainInterfaceData.ComputeMethodId(method); var methodType = method; // Generate the switch label for this interface id. var methodIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId))); // Generate the switch body. var methodInvokeStatement = generateMethodHandler(methodType); methodCases.Add( SF.SwitchSection().AddLabels(methodIdSwitchLabel).AddStatements(methodInvokeStatement)); } // Generate the switch label for this interface id. var interfaceIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId))); // Generate the default case, which will throw a NotImplementedException. var errorMessage = SF.BinaryExpression( SyntaxKind.AddExpression, "interfaceId=".GetLiteralExpression(), SF.BinaryExpression( SyntaxKind.AddExpression, SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId)), SF.BinaryExpression( SyntaxKind.AddExpression, ",methodId=".GetLiteralExpression(), methodIdArgument))); var throwStatement = SF.ThrowStatement( SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(errorMessage))); var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement); // Generate switch statements for the methods in this interface. var methodSwitchStatements = SF.SwitchStatement(methodIdArgument).AddSections(methodCases.ToArray()).AddSections(defaultCase); // Generate the switch section for this interface. interfaceCases.Add( SF.SwitchSection().AddLabels(interfaceIdSwitchLabel).AddStatements(methodSwitchStatements)); } return(interfaceCases.ToArray()); }
/// <summary> /// Generates invoker methods. /// </summary> /// <param name="grainType">The grain type.</param> /// <param name="onEncounteredType"> /// The callback which is invoked when a type is encountered. /// </param> /// <returns>Invoker methods for the provided grain type.</returns> private static MemberDeclarationSyntax[] GenerateInvokeMethods(Type grainType, Action <Type> onEncounteredType) { var baseReference = SF.BaseExpression(); var methods = GrainInterfaceData.GetMethods(grainType); var members = new List <MemberDeclarationSyntax>(); foreach (var method in methods) { onEncounteredType(method.ReturnType); var methodId = GrainInterfaceData.ComputeMethodId(method); var methodIdArgument = SF.Argument(SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId))); // Construct a new object array from all method arguments. var parameters = method.GetParameters(); var body = new List <StatementSyntax>(); foreach (var parameter in parameters) { onEncounteredType(parameter.ParameterType); if (typeof(IGrainObserver).IsAssignableFrom(parameter.ParameterType)) { body.Add( SF.ExpressionStatement( CheckGrainObserverParamInternalExpression.Invoke() .AddArgumentListArguments(SF.Argument(parameter.Name.ToIdentifierName())))); } } // Get the parameters argument value. ExpressionSyntax args; if (parameters.Length == 0) { args = SF.LiteralExpression(SyntaxKind.NullLiteralExpression); } else { args = SF.ArrayCreationExpression(typeof(object).GetArrayTypeSyntax()) .WithInitializer( SF.InitializerExpression(SyntaxKind.ArrayInitializerExpression) .AddExpressions(parameters.Select(GetParameterForInvocation).ToArray())); } var options = GetInvokeOptions(method); // Construct the invocation call. if (method.ReturnType == typeof(void)) { var invocation = SF.InvocationExpression(baseReference.Member("InvokeOneWayMethod")) .AddArgumentListArguments(methodIdArgument) .AddArgumentListArguments(SF.Argument(args)); if (options != null) { invocation = invocation.AddArgumentListArguments(options); } body.Add(SF.ExpressionStatement(invocation)); } else { var returnType = method.ReturnType == typeof(Task) ? typeof(object) : method.ReturnType.GenericTypeArguments[0]; var invocation = SF.InvocationExpression(baseReference.Member("InvokeMethodAsync", returnType)) .AddArgumentListArguments(methodIdArgument) .AddArgumentListArguments(SF.Argument(args)); if (options != null) { invocation = invocation.AddArgumentListArguments(options); } body.Add(SF.ReturnStatement(invocation)); } members.Add(method.GetDeclarationSyntax().AddBodyStatements(body.ToArray())); } return(members.ToArray()); }
protected override string GetBasicMethodImpl(MethodInfo methodInfo) { string invokeArguments = GetInvokeArguments(methodInfo); int methodId = GrainInterfaceData.ComputeMethodId(methodInfo); string methodImpl; string optional = null; if (GrainInterfaceData.IsReadOnly(methodInfo)) { optional = ", options: global::Orleans.CodeGeneration.InvokeMethodOptions.ReadOnly"; } if (GrainInterfaceData.IsUnordered(methodInfo)) { if (optional == null) { optional = ", options: "; } else { optional += " | "; } optional += " global::Orleans.CodeGeneration.InvokeMethodOptions.Unordered"; } if (GrainInterfaceData.IsAlwaysInterleave(methodInfo)) { if (optional == null) { optional = ", options: "; } else { optional += " | "; } optional += " global::Orleans.CodeGeneration.InvokeMethodOptions.AlwaysInterleave"; } if (methodInfo.ReturnType == typeof(void)) { methodImpl = string.Format(@" base.InvokeOneWayMethod({0}, {1} {2});", methodId, invokeArguments.Equals(string.Empty) ? "null" : String.Format("new object[] {{{0}}}", invokeArguments), optional); } else { if (methodInfo.ReturnType == typeof(Task)) { methodImpl = string.Format(@" return base.InvokeMethodAsync<object>({0}, {1} {2});", methodId, invokeArguments.Equals(string.Empty) ? "null" : String.Format("new object[] {{{0}}}", invokeArguments), optional); } else { methodImpl = string.Format(@" return base.InvokeMethodAsync<{0}>({1}, {2} {3});", GetActualMethodReturnType(methodInfo.ReturnType, SerializeFlag.NoSerialize), methodId, invokeArguments.Equals(string.Empty) ? "null" : String.Format("new object[] {{{0}}}", invokeArguments), optional); } } return(GetParamGuardCheckStatements(methodInfo) + methodImpl); }
protected override string GetBasicMethodImpl(MethodInfo methodInfo) { var invokeArguments = GetInvokeArguments(methodInfo); int methodId = GrainInterfaceData.ComputeMethodId(methodInfo); string methodImpl; string optional = null; if (GrainInterfaceData.IsReadOnly(methodInfo)) { optional = ", options:= Global.Orleans.CodeGeneration.InvokeMethodOptions.ReadOnly"; } if (GrainInterfaceData.IsUnordered(methodInfo)) { if (optional == null) { optional = ", options:= "; } else { optional += " | "; } optional += " Global.Orleans.CodeGeneration.InvokeMethodOptions.Unordered"; } if (GrainInterfaceData.IsAlwaysInterleave(methodInfo)) { if (optional == null) { optional = ", options:= "; } else { optional += " | "; } optional += " Global.Orleans.CodeGeneration.InvokeMethodOptions.AlwaysInterleave"; } if (methodInfo.ReturnType == typeof(void)) { methodImpl = string.Format(@" MyBase.InvokeOneWayMethod({0}, New System.Object() {{{1}}} {2})", methodId, invokeArguments, optional); } else { if (methodInfo.ReturnType == typeof(Task)) { methodImpl = string.Format(@" Return MyBase.InvokeMethodAsync(Of System.Object)({0}, New System.Object() {{{1}}} {2})", methodId, invokeArguments, optional); } else { methodImpl = string.Format(@" Return MyBase.InvokeMethodAsync(Of {0})({1}, New System.Object() {{{2}}} {3})", GetActualMethodReturnType(methodInfo.ReturnType, SerializeFlag.NoSerialize), methodId, invokeArguments, optional); } } return(GetParamGuardCheckStatements(methodInfo) + methodImpl); }