/// <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))); }
public ExpressionSyntax GetRoslynExpression(RoslynExpressionContext context) { var manager = context.GetService(typeof(IGuildOptionsManager)); var optionsType = context.ExpectedType.GetGenericArguments()[0]; var typeSyntax = S.ParseTypeName(optionsType.FullName.Replace('+', '.')); var getName = S.GenericName(nameof(SettingExtensions.GetOptionsAsync)).WithTypeArgumentList(S.TypeArgumentList().AddArguments(typeSyntax)); var get = S.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, manager, getName); var guildId = S.BinaryExpression( SyntaxKind.CoalesceExpression, context.GetRequestProperty(nameof(MessageRequest.GuildId)), S.ThrowExpression(S.ObjectCreationExpression( S.IdentifierName("InvalidOperationException"), S.ArgumentList().AddArguments(S.Argument(S.LiteralExpression(SyntaxKind.StringLiteralExpression, S.Literal(GuildIdNotDefined)))), null )) ); var invoke = S.InvocationExpression(get, S.ArgumentList().AddArguments(S.Argument(guildId))); return(S.AwaitExpression(invoke)); }
/// <summary> /// Create a new <see cref="ExpressionSyntax"/> that invokes the <see cref="method"/>. /// </summary> /// <param name="moduleType">The module type.</param> /// <param name="method">The method to invoke.</param> /// <returns>The <see cref="ExpressionSyntax"/>.</returns> private ExpressionSyntax InvokeCommand(Type moduleType, MethodInfo method) { var moduleSyntaxType = S.ParseTypeName(moduleType.FullName.Replace('+', '.')); var listSyntax = S.ArgumentList(); var constructor = moduleType.GetConstructors().FirstOrDefault(); if (constructor != null) { listSyntax = listSyntax.AddArguments(constructor.GetParameters().Select(p => S.Argument(GetValueFactory(p))).ToArray()); } var moduleInstance = S.ObjectCreationExpression(moduleSyntaxType).WithArgumentList(listSyntax); var contextProperty = moduleType .GetProperties() .FirstOrDefault(p => p.GetCustomAttributes <ModuleContextAttribute>().Any()); if (contextProperty != null) { var contextInstance = S.ObjectCreationExpression(ModuleContextType) .WithInitializer( S.InitializerExpression( SyntaxKind.ObjectInitializerExpression, S.SingletonSeparatedList <ExpressionSyntax>( S.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, S.IdentifierName(nameof(ModuleContext.Context)), S.IdentifierName(ArgumentContext) )))); moduleInstance = moduleInstance.WithInitializer( S.InitializerExpression( SyntaxKind.ObjectInitializerExpression, S.SingletonSeparatedList <ExpressionSyntax>( S.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, S.IdentifierName(contextProperty.Name), contextInstance )))); } ExpressionSyntax invoke = S.InvocationExpression( S.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, moduleInstance, S.IdentifierName(method.Name) ), S.ArgumentList().AddArguments(method.GetParameters().Select(p => S.Argument(GetValueFactory(p))).ToArray()) ); if (method.ReturnType == typeof(Task) || method.ReturnType == typeof(ValueTask)) { invoke = S.AwaitExpression(invoke); } else if (method.ReturnType != typeof(void)) { throw new InvalidOperationException($"The return type {method.ReturnType.Name} is not supported."); } return(invoke); }
/// <summary> /// Generates syntax to invoke a method on a grain. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="grain"> /// The grain instance expression. /// </param> /// <param name="method"> /// The method. /// </param> /// <param name="arguments"> /// The arguments expression. /// </param> /// <returns> /// Syntax to invoke a method on a grain. /// </returns> private static StatementSyntax[] GenerateInvokeForMethod( Type grainType, IdentifierNameSyntax grain, MethodInfo method, ExpressionSyntax arguments) { var castGrain = SF.ParenthesizedExpression(SF.CastExpression(grainType.GetTypeSyntax(), grain)); // Construct expressions to retrieve each of the method's parameters. 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 arg = SF.CastExpression( parameterType, SF.ElementAccessExpression(arguments).AddArgumentListArguments(indexArg)); parameters.Add(arg); } // If the method is a generic method definition, use the generic method invoker field to invoke the method. if (method.IsGenericMethodDefinition) { var invokerFieldName = GetGenericMethodInvokerFieldName(method); var invokerCall = SF.InvocationExpression( SF.IdentifierName(invokerFieldName) .Member((GenericMethodInvoker invoker) => invoker.Invoke(null, null))) .AddArgumentListArguments(SF.Argument(grain), SF.Argument(arguments)); return(new StatementSyntax[] { SF.ReturnStatement(SF.AwaitExpression(invokerCall)) }); } // Invoke the method. var grainMethodCall = SF.InvocationExpression(castGrain.Member(method.Name)) .AddArgumentListArguments(parameters.Select(SF.Argument).ToArray()); // For void methods, invoke the method and return null. if (method.ReturnType == typeof(void)) { return(new StatementSyntax[] { SF.ExpressionStatement(grainMethodCall), SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)) }); } // For methods which return non-generic Task, await the method and return null. if (method.ReturnType == typeof(Task)) { return(new StatementSyntax[] { SF.ExpressionStatement(SF.AwaitExpression(grainMethodCall)), SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)) }); } if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition().FullName == "System.Threading.Tasks.ValueTask`1") { var convertToTaskResult = SF.IdentifierName("AsTask"); // Converting ValueTask method result to Task since "Invoke" method should return Task. // Temporary solution. Need to change when Orleans will be using ValueTask instead of Task. grainMethodCall = SF.InvocationExpression( SF.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SF.ExpressionStatement(grainMethodCall).Expression, convertToTaskResult)); } return(new StatementSyntax[] { SF.ReturnStatement(SF.AwaitExpression(grainMethodCall)) }); }
/// <summary> /// Generates syntax to invoke a method on a grain. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="grain"> /// The grain instance expression. /// </param> /// <param name="method"> /// The method. /// </param> /// <param name="arguments"> /// The arguments expression. /// </param> /// <returns> /// Syntax to invoke a method on a grain. /// </returns> private static StatementSyntax[] GenerateInvokeForMethod( Type grainType, IdentifierNameSyntax grain, MethodInfo method, ExpressionSyntax arguments) { var castGrain = SF.ParenthesizedExpression(SF.CastExpression(grainType.GetTypeSyntax(), grain)); // Construct expressions to retrieve each of the method's parameters. 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 arg = SF.CastExpression( parameterType, SF.ElementAccessExpression(arguments).AddArgumentListArguments(indexArg)); parameters.Add(arg); } // If the method is a generic method definition, use the generic method invoker field to invoke the method. if (method.IsGenericMethodDefinition) { var invokerFieldName = GetGenericMethodInvokerFieldName(method); var invokerCall = SF.InvocationExpression( SF.IdentifierName(invokerFieldName) .Member((GenericMethodInvoker invoker) => invoker.Invoke(null, null))) .AddArgumentListArguments(SF.Argument(grain), SF.Argument(arguments)); return(new StatementSyntax[] { SF.ReturnStatement(SF.AwaitExpression(invokerCall)) }); } // Invoke the method. var grainMethodCall = SF.InvocationExpression(castGrain.Member(method.Name)) .AddArgumentListArguments(parameters.Select(SF.Argument).ToArray()); // For void methods, invoke the method and return null. if (method.ReturnType == typeof(void)) { return(new StatementSyntax[] { SF.ExpressionStatement(grainMethodCall), SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)) }); } // For methods which return non-generic Task, await the method and return null. if (method.ReturnType == typeof(Task)) { return(new StatementSyntax[] { SF.ExpressionStatement(SF.AwaitExpression(grainMethodCall)), SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)) }); } return(new StatementSyntax[] { SF.ReturnStatement(SF.AwaitExpression(grainMethodCall)) }); }