public ITypeInfo GetTypeInfo(IConfigurationFileElement requestingConfigurationFileElement, string typeAttributeName, string assemblyAttributeName, string typeRefAttributeName, IEnumerable <ITypeInfo> genericTypeParameters) { ITypeInfo tryGetKnownTypeInfo() { // Lets have this in a block, so that typeInfo is not accessible in the rst of the code. if (TryGetPrimitiveType(requestingConfigurationFileElement, out var typeInfo)) { return(typeInfo); } if (requestingConfigurationFileElement.HasAttribute(typeRefAttributeName)) { if (requestingConfigurationFileElement.HasAttribute(typeAttributeName) || requestingConfigurationFileElement.HasAttribute(assemblyAttributeName)) { throw new ConfigurationParseException(requestingConfigurationFileElement, $"Attributes '{typeAttributeName}' and '{assemblyAttributeName}' cannot be used to specify a type, if attribute '{typeRefAttributeName}' is used."); } var typeRefAttributeValue = requestingConfigurationFileElement.GetAttributeValue(typeRefAttributeName); var typeDefinition = requestingConfigurationFileElement.GetTypeDefinition(typeRefAttributeValue); if (typeDefinition?.ValueTypeInfo == null) { throw new ConfigurationParseException(requestingConfigurationFileElement, $"Invalid value of attribute '{typeRefAttributeName}'. Type definition with alias '{typeRefAttributeValue}' was not found in section '{ConfigurationFileElementNames.TypeDefinitions}'."); } return(typeDefinition?.ValueTypeInfo); } return(null); } var typeInfo2 = tryGetKnownTypeInfo(); if (typeInfo2 != null) { _pluginAssemblyTypeUsageValidator.Validate(requestingConfigurationFileElement, typeInfo2); return(typeInfo2); } if (!requestingConfigurationFileElement.HasAttribute(typeAttributeName)) { throw new ConfigurationParseException(requestingConfigurationFileElement, $"A value for either '{typeRefAttributeName}' or '{typeAttributeName}' should be provided. If attribute '{typeAttributeName}' is present, an optional attribute '{assemblyAttributeName}' value can be provided as well, to enforce that the type is in specified assembly."); } var typeAttributeValue = requestingConfigurationFileElement.GetAttributeValue <string>(typeAttributeName); return(GetTypeInfoFromTypeFullName(requestingConfigurationFileElement, typeAttributeValue, genericTypeParameters, typeAttributeValue, assemblyAttributeName)); }
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)); }