/*Throws an exception if single method is not found.*/
        private MethodInfo GetMethodInfoInClassOrParents([NotNull] string methodName,
                                                         [NotNull, ItemNotNull] Type[] parameterTypes)
        {
            StringBuilder errorMessage;
            var           matchedMethodInfos = new List <MethodInfo>();

            MethodInfo findMethodInfoInType(Type type)
            {
                foreach (var methodInfo in type.GetMethods())
                {
                    if (Helpers.IsMethodAMatch(methodInfo, methodName, parameterTypes) &&
                        methodInfo.ReturnType == ValueTypeInfo.Type)
                    {
                        return(methodInfo);
                    }
                }

                return(null);
            }

            void appendMethodParametersDescriptionOnInvalidSignature()
            {
                var parametersStrBldr = new StringBuilder();

                parametersStrBldr.Append("Method parameters used for lookup are: ");

                if (parameterTypes.Length == 0)
                {
                    parametersStrBldr.AppendLine("no parameters.");
                }
                else
                {
                    parametersStrBldr.AppendLine(string.Join(", ",
                                                             MethodSignatureElement.Parameters.Select(x => x.ValueTypeInfo.TypeCSharpFullName)));
                }

                errorMessage.AppendLine(parametersStrBldr.ToString());
                errorMessage.AppendLine("Note, currently methods that use in, ref, out keywords are not considered.");
            }

            if (DeclaringTypeInfoInAttribute != null)
            {
                var matchedMethodInfo = findMethodInfoInType(DeclaringTypeInfoInAttribute.Type);

                if (matchedMethodInfo != null)
                {
                    return(matchedMethodInfo);
                }

                errorMessage = new StringBuilder();
                errorMessage.AppendFormat("Method named '{0}', with return type '{1}' and the specified parameters was not found in interface '{2}', specified in  attribute '{3}'.",
                                          methodName, ValueTypeInfo.TypeCSharpFullName, DeclaringTypeInfoInAttribute.TypeCSharpFullName, ConfigurationFileAttributeNames.DeclaringInterface);

                errorMessage.AppendLine();

                appendMethodParametersDescriptionOnInvalidSignature();

                errorMessage.AppendLine("Remove the attribute to look in auto-implemented interface, and all the base interfaces.");
                throw new ConfigurationParseException(this, errorMessage.ToString());
            }

            void processType(Type type, ref bool stopProcessing2)
            {
                var methodInfo = findMethodInfoInType(type);

                if (methodInfo != null)
                {
                    matchedMethodInfos.Add(methodInfo);
                    if (type == ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.Type)
                    {
                        stopProcessing2 = true;
                    }
                }
            }

            var stopProcessing = false;

            TypeMemberLookupHelper.ProcessTypeImplementedInterfacesAndBaseTypes(
                ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.Type,
                processType, ref stopProcessing);

            if (matchedMethodInfos.Count == 1)
            {
                return(matchedMethodInfos[0]);
            }

            errorMessage = new StringBuilder();

            errorMessage.AppendFormat("Method with name '{0}', with return type '{1}' and the specified parameters ",
                                      methodName, ValueTypeInfo.TypeCSharpFullName);

            if (matchedMethodInfos.Count == 0)
            {
                errorMessage.AppendFormat("was not found in auto-generated interface '{0}' or any of its parents.",
                                          ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.TypeCSharpFullName);
                errorMessage.AppendLine();

                appendMethodParametersDescriptionOnInvalidSignature();
            }
            else
            {
                errorMessage.AppendFormat("was not found in auto-generated interface '{0}', however a method with this name, signature, and return type occurs multiple times in parents of interface '{0}'.",
                                          ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.TypeCSharpFullName);
                errorMessage.AppendLine();
                errorMessage.AppendLine($"Please use attribute '{ConfigurationFileAttributeNames.DeclaringInterface}', to explicitly specify the type, where the auto-implemented method is declared.");

                //--Example of proxy service--
                errorMessage.AppendFormat($"Note, if necessary, you can use '{0}' to proxy the service '{1}'.",
                                          ConfigurationFileElementNames.ProxyService, ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.TypeCSharpFullName);
                errorMessage.AppendLine();

                errorMessage.AppendLine(MessagesHelper.GenerateProxyServiceExample(matchedMethodInfos[0].DeclaringType,
                                                                                   ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.Type));

                // List of parent types
                appendMethodParametersDescriptionOnInvalidSignature();
                errorMessage.AppendLine(
                    string.Format("The following is the list of interfaces, where the method was found: {0}",
                                  string.Join(", ", matchedMethodInfos.Select(x => x.DeclaringType.GetTypeNameInCSharpClass()))));
            }

            throw new ConfigurationParseException(this, errorMessage.ToString());
        }
예제 #2
0
        public ClassMemberData GetClassMemberData(IConfigurationFileElement configurationFileElement, string classMemberPath,
                                                  IEnumerable <IParameter> parameters)
        {
            ITypeInfo classInfo = null;
            ITypeInfo memberTypeInfo;
            string    classMemberName = null;

            Type[] parameterTypes = parameters.Select(x => x.ValueTypeInfo.Type).ToArray();

            var allMatchedMemberInfos = new List <MemberInfo>();
            var isStaticMember        = true;
            var classMemberCategory   = ClassMemberCategory.Field;

            var lastIndexofDot = classMemberPath.LastIndexOf('.');

            if (lastIndexofDot > 0 && lastIndexofDot + 1 < classMemberPath.Length)
            {
                classMemberName = classMemberPath.Substring(lastIndexofDot + 1).Trim();
            }

            if (string.IsNullOrEmpty(classMemberName))
            {
                throw new ConfigurationParseException(configurationFileElement, $"No class member is specified in '{classMemberPath}'. {ExamplesOfValidClassPaths}");
            }

            var typeFullName = classMemberPath.Substring(0, lastIndexofDot).Trim();

            if (typeFullName.Length == 0)
            {
                throw new ConfigurationParseException(configurationFileElement, $"No class name is provided in {classMemberPath}. {ExamplesOfValidClassPaths}");
            }

            INamedTypeDefinitionElement namedTypeDefinitionElement = null;

            if (!typeFullName.Contains("."))
            {
                namedTypeDefinitionElement = configurationFileElement.GetTypeDefinition(typeFullName);

                if (namedTypeDefinitionElement != null)
                {
                    classInfo = namedTypeDefinitionElement.ValueTypeInfo;
                    _pluginAssemblyTypeUsageValidator.Validate(configurationFileElement, classInfo);
                }
            }

            if (classInfo == null)
            {
                classInfo = _typeHelper.GetTypeInfoFromTypeFullName(configurationFileElement, typeFullName);
            }

            if (classInfo.Type.IsEnum)
            {
                if (classInfo.Type.GetEnumNames().FirstOrDefault(x => classMemberName.Equals(x, StringComparison.Ordinal)) == null)
                {
                    throw new ConfigurationParseException(configurationFileElement, $"Enumeration value '{classMemberName}' is not defined in enumeration '{classInfo.TypeCSharpFullName}'.");
                }

                allMatchedMemberInfos.Add(classInfo.Type.GetMember(classMemberName).First());
                classMemberCategory = ClassMemberCategory.EnumValue;
                isStaticMember      = true;
                memberTypeInfo      = classInfo;
            }
            else
            {
                Type memberReturnType = null;

                void processType(Type type, ref bool stopProcessingParam)
                {
                    MemberInfo memberInfo = null;

                    try
                    {
                        if (parameterTypes.Length > 0)
                        {
                            // Lets try to find a method first.
                            var methodInfo = type.GetMethods().FirstOrDefault(x =>
                                                                              Helpers.IsMethodAMatch(x, classMemberName, parameterTypes));

                            if (methodInfo != null)
                            {
                                memberInfo = methodInfo;

                                classMemberCategory = ClassMemberCategory.Method;
                                isStaticMember      = methodInfo.IsStatic;
                                memberReturnType    = methodInfo.ReturnType;
                            }

                            return;
                        }

                        var memberInfos = type.GetMembers().Where(x =>
                                                                  classMemberName.Equals(x.Name, StringComparison.Ordinal)).ToList();

                        if (memberInfos.Count == 0)
                        {
                            return;
                        }


                        if (memberInfos[0] is MethodInfo)
                        {
                            var methodInfo = (MethodInfo)memberInfos.FirstOrDefault(x => x is MethodInfo methodInfo2 &&
                                                                                    methodInfo2.IsPublic &&
                                                                                    methodInfo2.GetParameters().Length == 0);
                            if (methodInfo == null)
                            {
                                return;
                            }

                            memberInfo          = methodInfo;
                            classMemberCategory = ClassMemberCategory.Method;
                            isStaticMember      = methodInfo.IsStatic;
                            memberReturnType    = methodInfo.ReturnType;
                        }
                        else
                        {
                            memberInfo = memberInfos[0];

                            if (memberInfo is FieldInfo fieldInfo)
                            {
                                if (!fieldInfo.IsPublic)
                                {
                                    return;
                                }

                                classMemberCategory = ClassMemberCategory.Field;
                                isStaticMember      = fieldInfo.IsStatic || fieldInfo.IsLiteral;
                                memberReturnType    = fieldInfo.FieldType;
                            }
                            else if (memberInfo is PropertyInfo propertyInfo)
                            {
                                var getMethod = propertyInfo.GetGetMethod();

                                if (!getMethod.IsPublic)
                                {
                                    return;
                                }

                                classMemberCategory = ClassMemberCategory.Property;
                                isStaticMember      = getMethod.IsStatic;
                                memberReturnType    = getMethod.ReturnType;
                            }
                        }
                    }
                    finally
                    {
                        if (memberInfo != null)
                        {
                            allMatchedMemberInfos.Add(memberInfo);

                            if (type == classInfo.Type)
                            {
                                stopProcessingParam = true;
                            }
                        }
                    }
                }

                var stopProcessing = false;
                _typeMemberLookupHelper.ProcessTypeImplementedInterfacesAndBaseTypes(classInfo.Type, processType, ref stopProcessing);

                if (allMatchedMemberInfos.Count == 1)
                {
                    memberTypeInfo = _typeHelper.GetTypeInfoFromType(configurationFileElement, memberReturnType);
                }
                else
                {
                    var errorMessage = new StringBuilder();
                    errorMessage.AppendFormat("Member with name '{0}'", classMemberName);

                    if (parameterTypes.Length > 0)
                    {
                        errorMessage.AppendFormat(" and parameters of types: ({0})",
                                                  string.Join(",", parameters.Select(x => x.ValueTypeInfo.TypeCSharpFullName)));
                    }
                    else
                    {
                        errorMessage.Append(" and zero parameters");
                    }


                    if (allMatchedMemberInfos.Count == 0)
                    {
                        errorMessage.AppendFormat(" was not found in type '{0}' or any of its parents.", classInfo.TypeCSharpFullName);
                        errorMessage.AppendLine();
                    }
                    else
                    {
                        errorMessage.AppendFormat(" was not found in type '{0}', however a member with this name occurs multiple times in parents of type '{0}'.",
                                                  classInfo.TypeCSharpFullName);
                        errorMessage.AppendLine();

                        errorMessage.AppendLine("Please specify one of the parent types where the member is declared.");

                        errorMessage.AppendFormat($"Note, if necessary, you can use '{0}' to proxy the service '{1}'.",
                                                  ConfigurationFileElementNames.ProxyService, classInfo.TypeCSharpFullName);
                        errorMessage.AppendLine();

                        errorMessage.AppendLine(MessagesHelper.GenerateProxyServiceExample(allMatchedMemberInfos[0].DeclaringType, classInfo.Type));

                        errorMessage.AppendLine(
                            string.Format("The following is the list of types, where the member named '{0}' was found: {1}",
                                          classMemberName,
                                          string.Join(", ", allMatchedMemberInfos.Select(x => x.DeclaringType.GetTypeNameInCSharpClass()))));
                    }

                    throw new ConfigurationParseException(configurationFileElement, errorMessage.ToString());
                }
            }

            return(new ClassMemberData(classInfo, memberTypeInfo, allMatchedMemberInfos[0], parameters, !isStaticMember, classMemberCategory));
        }
        /*Throws an exception if single method is not found.*/
        private PropertyInfo GetPropertyInfoInClassOrParents([NotNull] string propertyName)
        {
            StringBuilder errorMessage;
            var           matchedPropertyInfos = new List <PropertyInfo>();

            PropertyInfo findPropertyInfoInType(Type type)
            {
                foreach (var propertyInfo in type.GetProperties())
                {
                    if (!propertyInfo.Name.Equals(propertyName, StringComparison.Ordinal))
                    {
                        continue;
                    }

                    var getMethodInfo = propertyInfo.GetMethod;

                    if (getMethodInfo != null && getMethodInfo.IsPublic && getMethodInfo.ReturnType == ValueTypeInfo.Type)
                    {
                        return(propertyInfo);
                    }
                }

                return(null);
            }

            if (DeclaringTypeInfoInAttribute != null)
            {
                var matchedPropertyInfo = findPropertyInfoInType(DeclaringTypeInfoInAttribute.Type);

                if (matchedPropertyInfo != null)
                {
                    return(matchedPropertyInfo);
                }

                errorMessage = new StringBuilder();
                errorMessage.AppendFormat("Property named '{0}', and with return type '{1}' was not found in interface '{2}', specified in  attribute '{3}'.",
                                          propertyName, ValueTypeInfo.TypeCSharpFullName, DeclaringTypeInfoInAttribute.TypeCSharpFullName, ConfigurationFileAttributeNames.DeclaringInterface);

                errorMessage.AppendLine();
                errorMessage.AppendLine("Remove the attribute to look in auto-implemented interface, and all the base interfaces.");
                throw new ConfigurationParseException(this, errorMessage.ToString());
            }

            void processType(Type type, ref bool stopProcessing2)
            {
                var propertyInfo = findPropertyInfoInType(type);

                if (propertyInfo != null)
                {
                    matchedPropertyInfos.Add(propertyInfo);

                    if (type == ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.Type)
                    {
                        stopProcessing2 = true;
                    }
                }
            }

            var stopProcessing = false;

            TypeMemberLookupHelper.ProcessTypeImplementedInterfacesAndBaseTypes(
                ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.Type,
                processType, ref stopProcessing);

            if (matchedPropertyInfos.Count == 1)
            {
                return(matchedPropertyInfos[0]);
            }

            errorMessage = new StringBuilder();

            errorMessage.AppendFormat("Property with name '{0}', and with return type '{1}' ",
                                      propertyName, ValueTypeInfo.TypeCSharpFullName);

            if (matchedPropertyInfos.Count == 0)
            {
                errorMessage.AppendFormat("was not found in auto-generated interface '{0}' or any of its parents.",
                                          ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.TypeCSharpFullName);
                errorMessage.AppendLine();
            }
            else
            {
                errorMessage.AppendFormat("was not found in auto-generated interface '{0}', however a property with this name and return type occurs multiple times in parents of interface '{0}'.",
                                          ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.TypeCSharpFullName);
                errorMessage.AppendLine();
                errorMessage.AppendLine($"Please use attribute '{ConfigurationFileAttributeNames.DeclaringInterface}', to explicitly specify the type, where the auto-implemented property is declared.");

                //--Example of proxy service--
                errorMessage.AppendFormat($"Note, if necessary, you can use '{0}' to proxy the service '{1}'.",
                                          ConfigurationFileElementNames.ProxyService, ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.TypeCSharpFullName);
                errorMessage.AppendLine();

                errorMessage.AppendLine(MessagesHelper.GenerateProxyServiceExample(matchedPropertyInfos[0].DeclaringType,
                                                                                   ParentAutoGeneratedServiceElement.ImplementedInterfaceTypeInfo.Type));

                // List of parent types
                errorMessage.AppendLine(
                    string.Format("The following is the list of interfaces, where the property was found: {0}",
                                  string.Join(", ", matchedPropertyInfos.Select(x => x.DeclaringType.GetTypeNameInCSharpClass()))));
            }

            throw new ConfigurationParseException(this, errorMessage.ToString());
        }