/// <summary> /// Generates a wrapper method that takes arguments of the original method. /// </summary> protected virtual CodeTypeMember GetBasicReferenceMethod(MethodInfo methodInfo, CodeTypeParameterCollection genericTypeParam, bool isObserver) { SerializerGenerationManager.RecordTypeToGenerate(methodInfo.ReturnType); foreach (var paramInfo in methodInfo.GetParameters()) { SerializerGenerationManager.RecordTypeToGenerate(paramInfo.ParameterType); } CodeTypeReference returnType; if (!isObserver) { // Method is expected to return either a Task or a grain reference if (!GrainInterfaceData.IsTaskType(methodInfo.ReturnType) && !typeof(IAddressable).IsAssignableFrom(methodInfo.ReturnType)) { throw new InvalidOperationException( string.Format("Unsupported return type {0}. Method Name={1} Declaring Type={2}", methodInfo.ReturnType.FullName, methodInfo.Name, TypeUtils.GetFullName(methodInfo.DeclaringType, language))); } returnType = CreateCodeTypeReference(methodInfo.ReturnType, language); } else { returnType = new CodeTypeReference(typeof(void)); } var referenceMethod = new CodeMemberMethod { Name = methodInfo.Name, ReturnType = returnType }; foreach (var param in methodInfo.GetParameters()) { var paramName = GetParameterName(param); CodeParameterDeclarationExpression p = param.ParameterType.IsGenericType ? new CodeParameterDeclarationExpression( TypeUtils.GetParameterizedTemplateName(param.ParameterType, true, tt => CurrentNamespace != tt.Namespace && !ReferencedNamespaces.Contains(tt.Namespace), language), paramName) : new CodeParameterDeclarationExpression(param.ParameterType, paramName); p.Direction = FieldDirection.In; referenceMethod.Parameters.Add(p); } referenceMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; var pit = new CodeTypeReference(GetGenericTypeName(methodInfo.DeclaringType, type => { }, t => false)); referenceMethod.PrivateImplementationType = pit; var methodImpl = new CodeSnippetStatement(GetBasicMethodImpl(methodInfo)); referenceMethod.Statements.Add(methodImpl); return(referenceMethod); }
/// <summary> /// Gets the name of the result type differentiating promises from normal types. For promises it returns the type of the promised value instead of the promises type itself. /// </summary> protected string GetActualMethodReturnType(Type type, SerializeFlag flag) { if (!type.IsGenericType) { return(GetGenericTypeName(type, flag)); } if (GrainInterfaceData.IsTaskType(type)) { Type[] genericArguments = type.GetGenericArguments(); if (genericArguments.Length == 1) { return(GetGenericTypeName(genericArguments[0], flag)); } var errorMsg = String.Format("Unexpected number of arguments {0} for generic type {1} used as a return type. Only Type<T> are supported as generic return types of grain methods.", genericArguments.Length, type); ConsoleText.WriteError(errorMsg); throw new ApplicationException(errorMsg); } return(GetGenericTypeName(type, flag)); }
private string GetMethodDispatchSwitchForInterface(int interfaceId, InterfaceInfo interfaceInfo) { string methodSwitchBody = String.Empty; foreach (int methodId in interfaceInfo.Methods.Keys) { MethodInfo methodInfo = interfaceInfo.Methods[methodId]; var returnType = methodInfo.ReturnType; GetGenericTypeName(returnType); // Adds return type assembly and namespace to import / library lists if necessary var invokeGrainArgs = string.Empty; ParameterInfo[] paramInfoArray = methodInfo.GetParameters(); for (int count = 0; count < paramInfoArray.Length; count++) { invokeGrainArgs += string.Format("({0})arguments[{1}]", GetGenericTypeName(paramInfoArray[count].ParameterType), count); if (count < paramInfoArray.Length - 1) { invokeGrainArgs += ", "; } } // TODO: parameters for indexed properties string grainTypeName = GetGenericTypeName(interfaceInfo.InterfaceType); string methodName = methodInfo.Name; string invokeGrainMethod; if (!methodInfo.IsSpecialName) { invokeGrainMethod = string.Format("(({0})grain).{1}({2})", grainTypeName, methodName, invokeGrainArgs); } else if (methodInfo.Name.StartsWith("get_")) { invokeGrainMethod = string.Format("(({0})grain).{1}", grainTypeName, methodName.Substring(4)); } else if (methodInfo.Name.StartsWith("set_")) { invokeGrainMethod = string.Format("(({0})grain).{1} = {2}", grainTypeName, methodName.Substring(4), invokeGrainArgs); } else { // Should never happen throw new InvalidOperationException("Don't know how to handle method " + methodInfo); } string caseBodyStatements; if (returnType == typeof(void)) { caseBodyStatements = string.Format( @"{0}; return System.Threading.Tasks.Task.FromResult((object)true); ", invokeGrainMethod); } else if (GrainInterfaceData.IsTaskType(returnType)) { if (returnType != typeof(Task)) { GetGenericTypeName(returnType.GetGenericArguments()[0]); } if (returnType == typeof(Task)) { caseBodyStatements = string.Format( @"return {0}.ContinueWith(t => {{if (t.Status == System.Threading.Tasks.TaskStatus.Faulted) throw t.Exception; return (object)null; }}); ", invokeGrainMethod); } else { caseBodyStatements = string.Format( @"return {0}.ContinueWith(t => {{if (t.Status == System.Threading.Tasks.TaskStatus.Faulted) throw t.Exception; return (object)t.Result; }}); ", invokeGrainMethod); } } else { // Should never happen throw new InvalidOperationException(string.Format( "Don't know how to create invoker for method {0} with Id={1} of returnType={2}", methodInfo, methodId, returnType)); } methodSwitchBody += string.Format(@" case {0}: {1}", methodId, caseBodyStatements); } const string defaultCase = @"default: throw new NotImplementedException(""interfaceId=""+interfaceId+"",methodId=""+methodId);"; return(String.Format(@"case {0}: // {1} switch (methodId) {{ {2} {3} }}", interfaceId, interfaceInfo.InterfaceType.Name, methodSwitchBody, defaultCase)); }
private string GetMethodDispatchSwitchForInterface(int interfaceId, InterfaceInfo interfaceInfo) { var methodSwitchBody = String.Empty; foreach (int methodId in interfaceInfo.Methods.Keys) { var methodInfo = interfaceInfo.Methods[methodId]; var returnType = methodInfo.ReturnType; GetGenericTypeName(returnType); // Adds return type assembly and namespace to import / library lists if necessary var invokeGrainArgs = string.Empty; ParameterInfo[] paramInfoArray = methodInfo.GetParameters(); for (int count = 0; count < paramInfoArray.Length; count++) { invokeGrainArgs += string.Format("CType(arguments({1}),{0})", GetGenericTypeName(paramInfoArray[count].ParameterType), count); if (count < paramInfoArray.Length - 1) { invokeGrainArgs += ", "; } } // todo: parameters for indexed properties var grainTypeName = GetGenericTypeName(interfaceInfo.InterfaceType); var methodName = methodInfo.Name; string invokeGrainMethod; if (!methodInfo.IsSpecialName) { invokeGrainMethod = string.Format("CType(grain,{0}).{1}({2})", grainTypeName, methodName, invokeGrainArgs); } else if (methodInfo.Name.StartsWith("get_")) { invokeGrainMethod = string.Format("CType(grain,{0}).{1}", grainTypeName, methodName.Substring(4)); } else if (methodInfo.Name.StartsWith("set_")) { invokeGrainMethod = string.Format("CType(grain,{0}).{1} = {2}", grainTypeName, methodName.Substring(4), invokeGrainArgs); } else { // Should never happen throw new InvalidOperationException("Don't know how to handle method " + methodInfo); } string caseBodyStatements; if (returnType == typeof(void)) { caseBodyStatements = string.Format( @"{0} Return System.Threading.Tasks.Task.FromResult(CObj(True)) ", invokeGrainMethod); } else if (GrainInterfaceData.IsTaskType(returnType)) { if (returnType == typeof(Task)) { caseBodyStatements = string.Format( @" Return {0}.ContinueWith(Function(t) If t.Status = System.Threading.Tasks.TaskStatus.Faulted Then : Throw t.Exception : End If Return Nothing End Function) ", invokeGrainMethod); } else { caseBodyStatements = string.Format( @"Return {0}.ContinueWith(Function(t) CObj(t.Result)) ", invokeGrainMethod); } } else { // Should never happen throw new InvalidOperationException(string.Format( "Don't know how to create invoker for method {0} with Id={1} of returnType={2}", methodInfo, methodId, returnType)); } methodSwitchBody += string.Format(@" Case {0} {1}", methodId, caseBodyStatements); } var defaultCase = @" Case Else Throw New NotImplementedException(""interfaceId=""+interfaceId+"",methodId=""+methodId)"; return(String.Format(@"Case {0} ' {1} Select Case methodId {2} {3} End Select ", interfaceId, interfaceInfo.InterfaceType.Name, methodSwitchBody, defaultCase)); }
internal static void RecordTypeToGenerate(Type t) { var typeInfo = t.GetTypeInfo(); if (typeInfo.IsGenericParameter || ProcessedTypes.Contains(t) || TypesToProcess.Contains(t) || typeof(Exception).GetTypeInfo().IsAssignableFrom(t)) { return; } if (typeInfo.IsArray) { RecordTypeToGenerate(typeInfo.GetElementType()); return; } if (typeInfo.IsNestedPublic || typeInfo.IsNestedFamily || typeInfo.IsNestedPrivate) { Log.Warn( ErrorCode.CodeGenIgnoringTypes, "Skipping serializer generation for nested type {0}. If this type is used frequently, you may wish to consider making it non-nested.", t.Name); } if (typeInfo.IsGenericType) { var args = t.GetGenericArguments(); foreach (var arg in args) { if (!arg.IsGenericParameter) { RecordTypeToGenerate(arg); } } } if (typeInfo.IsInterface || typeInfo.IsAbstract || typeInfo.IsEnum || t == typeof(object) || t == typeof(void) || GrainInterfaceData.IsTaskType(t)) { return; } if (typeInfo.IsGenericType) { var def = typeInfo.GetGenericTypeDefinition(); if (def == typeof(Task <>) || (SerializationManager.GetSerializer(def) != null) || ProcessedTypes.Contains(def) || typeof(IAddressable).IsAssignableFrom(def)) { return; } if (def.Namespace != null && (def.Namespace.Equals("System") || def.Namespace.StartsWith("System."))) { Log.Warn( ErrorCode.CodeGenSystemTypeRequiresSerializer, "System type " + def.Name + " requires a serializer."); } else { TypesToProcess.Add(def); } return; } if (typeInfo.IsOrleansPrimitive() || (SerializationManager.GetSerializer(t) != null) || typeof(IAddressable).GetTypeInfo().IsAssignableFrom(t)) { return; } if (typeInfo.Namespace != null && (typeInfo.Namespace.Equals("System") || typeInfo.Namespace.StartsWith("System."))) { var message = "System type " + t.Name + " may require a custom serializer for optimal performance. " + "If you use arguments of this type a lot, consider asking the Orleans team to build a custom serializer for it."; Log.Warn(ErrorCode.CodeGenSystemTypeRequiresSerializer, message); return; } bool hasCopier = false; bool hasSerializer = false; bool hasDeserializer = false; foreach (var method in t.GetMethods(BindingFlags.Static | BindingFlags.Public)) { if (method.GetCustomAttributes(typeof(SerializerMethodAttribute), false).Length > 0) { hasSerializer = true; } else if (method.GetCustomAttributes(typeof(DeserializerMethodAttribute), false).Length > 0) { hasDeserializer = true; } if (method.GetCustomAttributes(typeof(CopierMethodAttribute), false).Length > 0) { hasCopier = true; } } if (hasCopier && hasSerializer && hasDeserializer) { return; } TypesToProcess.Add(t); }