private void ProcessNonImplementedMethodsAndPropertiesOnChildrenAdded() { void processType(Type type, ref bool stopProcessingParam) { foreach (var methodInfo in type.GetMethods()) { if ((methodInfo.Attributes & MethodAttributes.SpecialName) == MethodAttributes.SpecialName) { continue; } if (_methodInfoToSimilarOrSameAutoGeneratedServiceMethodElementMap.TryGetValue(methodInfo, out var similarOrSameAutoGeneratedServiceMethodElement)) { continue; } similarOrSameAutoGeneratedServiceMethodElement = _methods.FirstOrDefault( x => CanMethodBeReplacedWithAnotherMethod(methodInfo, x.ImplementedMehodInfo)); if (similarOrSameAutoGeneratedServiceMethodElement != null) { _methodInfoToSimilarOrSameAutoGeneratedServiceMethodElementMap[methodInfo] = similarOrSameAutoGeneratedServiceMethodElement; } } foreach (var propertyInfo in type.GetProperties()) { if ((propertyInfo.Attributes & PropertyAttributes.SpecialName) == PropertyAttributes.SpecialName) { continue; } if (_propertyInfoToSimilarOrSameAutoGeneratedServicePropertyElementMap.TryGetValue(propertyInfo, out var similarOrSameAutoGeneratedServicePropertyElement)) { continue; } similarOrSameAutoGeneratedServicePropertyElement = _properties.FirstOrDefault( x => propertyInfo.PropertyType.IsTypeAssignableFrom(x.ImplementedPropertyInfo.PropertyType)); if (similarOrSameAutoGeneratedServicePropertyElement != null) { _propertyInfoToSimilarOrSameAutoGeneratedServicePropertyElementMap[propertyInfo] = similarOrSameAutoGeneratedServicePropertyElement; } } } var stopProcessing = false; TypeMemberLookupHelper.ProcessTypeImplementedInterfacesAndBaseTypes(ImplementedInterfaceTypeInfo.Type, processType, ref stopProcessing); }
/*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()); }
public override void GenerateAutoImplementedServiceClassCSharp(IDynamicAssemblyBuilder dynamicAssemblyBuilder, string dynamicImplementationsNamespace, out string generatedClassFullName) { // Add assemblies referenced by service var className = $"{ImplementedInterfaceTypeInfo.Type.Name}_{GlobalsCoreAmbientContext.Context.GenerateUniqueId()}"; generatedClassFullName = $"{dynamicImplementationsNamespace}.{className}"; var classStrBldr = new StringBuilder(5000); var classMemberVariablesStrBldr = new StringBuilder(1000); classStrBldr.AppendLine(); classStrBldr.AppendLine("using System;"); classStrBldr.AppendLine($"namespace {dynamicImplementationsNamespace}"); classStrBldr.AppendLine("{"); classStrBldr.AppendLine($"public sealed class {className}: {ImplementedInterfaceTypeInfo.TypeCSharpFullName}"); classStrBldr.AppendLine("{"); void ProcessType(Type type, ref bool stopProcessingParam) { foreach (var methodInfo in type.GetMethods()) { if ((methodInfo.Attributes & MethodAttributes.SpecialName) > 0) { continue; } var methodSignature = GetMethodSignature(methodInfo); classStrBldr.Append(methodSignature); if (_methodInfoToSimilarOrSameAutoGeneratedServiceMethodElementMap.TryGetValue(methodInfo, out var autoGeneratedServiceMethodElement)) { if (autoGeneratedServiceMethodElement.ImplementedMehodInfo == methodInfo) { AddMethodBodyForImplementedMethod(dynamicAssemblyBuilder, autoGeneratedServiceMethodElement, classStrBldr, classMemberVariablesStrBldr); } else { AddMethodBodyForNonImplementedMethodWithSimilarImplementedMethod(dynamicAssemblyBuilder, methodInfo, autoGeneratedServiceMethodElement, classStrBldr); } } else { classStrBldr.AppendLine("{"); foreach (var outParameterInfo in methodInfo.GetParameters().Where(x => x.IsOut)) { classStrBldr.AppendLine($"{outParameterInfo.Name}=default({outParameterInfo.ParameterType.GetTypeNameInCSharpClass()});"); } if (methodInfo.ReturnType != typeof(void)) { classStrBldr.Append($"return default({methodInfo.ReturnType.GetTypeNameInCSharpClass()});"); classStrBldr.AppendLine(); } classStrBldr.AppendLine("}"); } classStrBldr.AppendLine(); } foreach (var propertyInfo in type.GetProperties()) { var propertyHeader = GetPropertyHeader(propertyInfo); void AddGetSet() { classStrBldr.Append(" { get;"); if (propertyInfo.SetMethod != null) { classStrBldr.Append(" set;"); } classStrBldr.Append("}"); } classStrBldr.Append(propertyHeader); if (_propertyInfoToSimilarOrSameAutoGeneratedServicePropertyElementMap.TryGetValue(propertyInfo, out var similarOrSameAutoGeneratedServicePropertyElement)) { var similarPropertyInfo = similarOrSameAutoGeneratedServicePropertyElement.ImplementedPropertyInfo; if (similarPropertyInfo == propertyInfo) { AddGetSet(); classStrBldr.AppendLine($"={similarOrSameAutoGeneratedServicePropertyElement.ReturnValueElement.GenerateValueCSharp(dynamicAssemblyBuilder)};"); } else { var privateVariableName = $"_{propertyInfo.DeclaringType.Name}_{propertyInfo.Name}_{GlobalsCoreAmbientContext.Context.GenerateUniqueId()}"; // Not, for nullable values and reference types, we can check for null, to set if the value was initialized. // however, to make it simple, and also to avoid calling the other class property every time, in case the other property // value is null, lets use the valueWasSet variable for all cases. var valueWasSetVariableName = $"{privateVariableName}_ValueWasSet"; classStrBldr.AppendLine(); classStrBldr.AppendLine("{"); classStrBldr.AppendLine("get"); classStrBldr.AppendLine("{"); classStrBldr.AppendLine($"if ({valueWasSetVariableName}) return {privateVariableName};"); classStrBldr.Append($"{privateVariableName}=(({similarPropertyInfo.DeclaringType.GetTypeNameInCSharpClass()})this)"); classStrBldr.AppendLine($".{similarPropertyInfo.Name};"); classStrBldr.AppendLine($"{valueWasSetVariableName}=true;"); classStrBldr.AppendLine($"return {privateVariableName};"); classStrBldr.AppendLine("}"); if (propertyInfo.SetMethod != null) { classStrBldr.AppendLine("set"); classStrBldr.AppendLine("{"); classStrBldr.AppendLine($"{privateVariableName}=value;"); classStrBldr.AppendLine($"{valueWasSetVariableName}=true;"); classStrBldr.AppendLine("}"); } classStrBldr.AppendLine("}"); classStrBldr.AppendLine($"private bool {valueWasSetVariableName};"); classStrBldr.AppendLine($"private {propertyInfo.PropertyType.GetTypeNameInCSharpClass()} {privateVariableName};"); } } else { AddGetSet(); classStrBldr.AppendLine(); } } } var stopProcessing = false; TypeMemberLookupHelper.ProcessTypeImplementedInterfacesAndBaseTypes(ImplementedInterfaceTypeInfo.Type, ProcessType, ref stopProcessing); classStrBldr.Append(classMemberVariablesStrBldr); // Close class classStrBldr.AppendLine("}"); // Close namespace classStrBldr.AppendLine("}"); dynamicAssemblyBuilder.AddCSharpFile(classStrBldr.ToString()); }
/*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()); }