/// <summary> /// The generate dispatch block for method. /// </summary> /// <param name="methodDescription"> /// The method description. /// </param> /// <param name="instance"> /// The instance. /// </param> /// <param name="event"> /// The event. /// </param> /// <returns> /// The <see cref="StatementSyntax"/>. /// </returns> private static StatementSyntax GenerateDispatchBlockForMethod(ActorMethodDescription methodDescription, IdentifierNameSyntax instance, IdentifierNameSyntax @event) { // Construct expressions to retrieve each of the method's parameters. var method = methodDescription.MethodInfo; var parameters = new List <ExpressionSyntax>(); var methodParameters = method.GetParameters().ToList(); for (var i = 0; i < methodParameters.Count; i++) { var parameter = methodParameters[i]; var parameterType = parameter.ParameterType.GetTypeSyntax(); var indexArg = SF.Argument( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(i))); var getArg = SF.InvocationExpression(@event.Member("Arg", parameterType)).AddArgumentListArguments(indexArg); parameters.Add(getArg); } var grainMethodCall = SF.InvocationExpression(instance.Member(method.Name)) .AddArgumentListArguments(parameters.Select(SF.Argument).ToArray()); return(SF.ReturnStatement(SF.InvocationExpression(grainMethodCall.Member("Box")))); }
/// <summary> /// Returns the types referenced by the provided <paramref name="method"/>. /// </summary> /// <param name="method"> /// The method. /// </param> /// <returns> /// The types referenced by the provided <paramref name="method"/>. /// </returns> public static IEnumerable <Type> GetTypes(ActorMethodDescription method) { foreach (var type in GetTypes(method.MethodInfo.ReturnType)) { yield return(type); } foreach ( var parameterType in method.MethodInfo.GetParameters().SelectMany(parameter => GetTypes(parameter.ParameterType))) { yield return(parameterType); } }
/// <summary> /// Returns syntax for individual switch cases within the <see cref="IEventInvoker{T}.GetArgumentTypes"/> method. /// </summary> /// <param name="methodDescription"> /// The method description. /// </param> /// <returns> /// Syntax for individual switch cases within the <see cref="IEventInvoker{T}.GetArgumentTypes"/> method. /// </returns> private static StatementSyntax GenerateGetTypeArgumentsSwitchBlock(ActorMethodDescription methodDescription) { var method = methodDescription.MethodInfo; var parameters = method.GetParameters().ToList(); var argumentTypes = parameters.Select(p => SF.TypeOfExpression(p.ParameterType.GetTypeSyntax())) .Cast <ExpressionSyntax>() .ToArray(); var argumentTypeArray = SF.ArrayCreationExpression(typeof(Type).GetArrayTypeSyntax()) .WithInitializer( SF.InitializerExpression(SyntaxKind.ArrayInitializerExpression).AddExpressions(argumentTypes)); return(SF.ReturnStatement(argumentTypeArray)); }
/// <summary> /// Generates a method. /// </summary> /// <param name="methodDescription"> /// The method description. /// </param> /// <returns> /// The generated method. /// </returns> /// <exception cref="ArgumentException"> /// The return type of the provided method is not supported. /// </exception> private static MethodDeclarationSyntax GenerateMethod(ActorMethodDescription methodDescription) { // Types var method = methodDescription.MethodInfo; Type asyncReturnType; if (!method.ReturnType.IsGenericType && (method.ReturnType == typeof(Task))) { asyncReturnType = typeof(void); } else if (method.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)) { asyncReturnType = method.ReturnType.GenericTypeArguments[0]; } else { throw new ArgumentException("Method return type is not Task or Task<T>."); } // Body statements var parameterReferences = method.GetParameters() .Select( p => SF.Argument(SF.CastExpression(typeof(object).GetTypeSyntax(), SF.IdentifierName(p.Name)))) .ToArray(); var writeEventMethod = SF.ThisExpression().Member((EventProducerBase <object> _) => _.WriteEvent(default(string), default(object), default(object))); var writeEvent = SF.ExpressionStatement( SF.AwaitExpression( SF.InvocationExpression(writeEventMethod) .AddArgumentListArguments(SF.Argument(methodDescription.Name.GetLiteralExpression())) .AddArgumentListArguments(parameterReferences))); var returnValue = asyncReturnType == typeof(void) ? null : SF.DefaultExpression(asyncReturnType.GetTypeSyntax()); // Build and return the method. return (SF.MethodDeclaration(method.ReturnType.GetTypeSyntax(), methodDescription.MethodInfo.Name) .AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.AsyncKeyword)) .AddParameterListParameters(method.GetParameterListSyntax()) .AddBodyStatements(writeEvent, SF.ReturnStatement(returnValue))); }
/// <summary> /// Returns syntax for dispatching <paramref name="event"/> to <paramref name="method"/>. /// </summary> /// <param name="event"> /// The event. /// </param> /// <param name="method"> /// The actor description. /// </param> /// <returns> /// Syntax for dispatching <paramref name="event"/> to <paramref name="method"/>. /// </returns> private static SwitchSectionSyntax GetMethodSwitchCase(ExpressionSyntax @event, ActorMethodDescription method) { var label = SF.CaseSwitchLabel(SF.LiteralExpression(SyntaxKind.StringLiteralExpression, SF.Literal(method.Name))); return (SF.SwitchSection() .AddLabels(label) .AddStatements( GenerateMethodDispatcher(@event, SF.IdentifierName("grain"), method.MethodInfo))); }