Пример #1
0
        /// <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);
        }
Пример #2
0
        /// <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));
        }
Пример #3
0
        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));
        }
Пример #4
0
        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));
        }
Пример #5
0
        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);
        }