private List <PropertyInfo> GetPropertiesToWrap(Type originalType, TypeToTypeWrapperOptions options) { var result = new List <PropertyInfo>(); var allTypeProperties = originalType.GetProperties(); foreach (var propertyInfo in allTypeProperties) { foreach (var includedPropertyName in options.IncludedProperties) { var regEx = NameToRegex(includedPropertyName); if (regEx.IsMatch(propertyInfo.Name) == false) { continue; } result.Add(propertyInfo); break; } } return(result); }
private static string GetTypeName(TypeToTypeWrapperOptions options, Type originalType) { if (options?.TypeNameGenerator != null) { return(options.TypeNameGenerator(options, originalType)); } return("GeneratedType"); }
public static Guid Add(Type type, TypeToTypeWrapperOptions options) { var id = Guid.NewGuid(); var factory = options.Factory; object Create() { return(factory(options, type)); } void OnConstructor(object instance) { if (options.OnConstructor == null) { return; } options.OnConstructor.Invoke(options, type, instance); } void OnBeforeMethod(object instance, MethodInfo methodInfo) { if (options.OnBeforeMethod == null) { return; } options.OnBeforeMethod.Invoke(options, type, instance, methodInfo); } void OnAfterMethod(object instance, MethodInfo methodInfo) { if (options.OnAfterMethod == null) { return; } options.OnAfterMethod.Invoke(options, type, instance, methodInfo); } var item = new TypeCacheItem() { Factory = Create, OnConstructor = OnConstructor, OnBeforeMethod = OnBeforeMethod, OnAfterMethod = OnAfterMethod }; Cache.Add(id, Create); Cache2.Add(id, item); return(id); }
private List <MethodInfo> GetMethodsToWrap(Type originalType, TypeToTypeWrapperOptions options) { var result = new List <MethodInfo>(); var allTypeMethods = originalType.GetMethods(); foreach (var methodInfo in allTypeMethods) { if (options.IncludeMethod(options, originalType, methodInfo) == false) { continue; } if (options.ExcludeMethod(options, originalType, methodInfo)) { continue; } if (options.IncludedMethods?.Any() != true) { result.Add(methodInfo); continue; } if (options.IncludedMethods?.Contains(methodInfo.Name) == true) { result.Add(methodInfo); continue; } foreach (var includedMethodName in options.IncludedMethods) { var regEx = NameToRegex(includedMethodName); if (regEx.IsMatch(methodInfo.Name) == false) { continue; } result.Add(methodInfo); break; } } return(result); }
private static void CreateWrapperProperty(TypeToTypeWrapperOptions options, StringBuilder code, PropertyInfo propertyInfo, Type originalType) { var originalPropertyName = propertyInfo.Name; code.AppendLine($"public {GetFriendlyName(propertyInfo.PropertyType, GetTypeName(options, originalType))} {originalPropertyName}"); code.AppendLine("{"); code.AppendLine("get"); code.AppendLine("{"); code.AppendLine($"return _instance.{originalPropertyName};"); code.AppendLine("}"); if (propertyInfo.CanWrite) { code.AppendLine("set"); code.AppendLine("{"); code.AppendLine($"_instance.{originalPropertyName} = value;"); code.AppendLine("}"); } code.AppendLine("}"); }
private static void AddReferences(CodeToAssemblyGenerator generator, List <Type> allTypes, TypeToTypeWrapperOptions options, Type originalType) { generator.ReferenceAssemblyContainingType <Action>(); generator.ReferenceAssemblyContainingType <DelegateCache>(); generator.ReferenceAssemblyContainingType <DelegateToTypeWrapper>(); foreach (var allType in allTypes) { generator.ReferenceAssembly(allType.Assembly); } if (options?.AdditionalReferences?.Any() == true) { foreach (var additionalReference in options.AdditionalReferences) { generator.ReferenceAssembly(additionalReference); } } if (options?.TypeAttributesGenerator != null) { var attrs = options.TypeAttributesGenerator(options, originalType); foreach (var attribute in attrs) { generator.ReferenceAssembly(attribute.GetType().Assembly); } } if (options?.Inherits != null) { generator.ReferenceAssembly(options.Inherits.Assembly); } }
private static void DoConversions(ParameterInfo[] parameters, List <ParameterConversionRule> conversionRules, List <string> constructorParameterNames, List <string> constructorParameterNamesWithTypes, List <string> constructorFieldNamesWithTypes, List <string> propertyNamesWithTypes, List <string> delegateMethodParameters, List <string> methodParameterNamesWithTypes, TypeToTypeWrapperOptions options, Type originalType) { for (var index = 0; index < parameters.Length; index++) { var parameterInfo = parameters[index]; var parameterType = parameterInfo.ParameterType; var parameterName = parameterInfo.Name ?? $"param{Guid.NewGuid().ToString().ToLowerInvariant().Replace("-", "")}"; var handled = false; foreach (var conversionRule in conversionRules) { var canHandle = conversionRule.CanHandle(parameterInfo); if (canHandle) { var conversionResult = conversionRule.Handle(parameterInfo); if (!string.IsNullOrWhiteSpace(conversionResult.Name)) { parameterName = conversionResult.Name; } if (conversionResult.ToConstructor) { constructorParameterNames.Add(parameterName); constructorParameterNamesWithTypes.Add($"{GetFriendlyName(parameterType, GetTypeName(options, originalType))} {parameterName}"); var fieldName = $"_{parameterName}"; constructorFieldNamesWithTypes.Add($"{GetFriendlyName(parameterType, GetTypeName(options, originalType))} {fieldName}"); delegateMethodParameters.Add(fieldName); handled = true; break; } if (conversionResult.ToPublicProperty) { var propertyName = $"{CultureInfo.InvariantCulture.TextInfo.ToTitleCase(parameterName)}"; if (string.Equals(parameterName, propertyName)) { propertyName = $"{propertyName}Prop"; } propertyNamesWithTypes.Add($"{GetFriendlyName(parameterType, GetTypeName(options, originalType))} {propertyName}"); delegateMethodParameters.Add(propertyName); handled = true; break; } methodParameterNamesWithTypes.Add($"{GetFriendlyName(parameterType, GetTypeName(options, originalType))} {parameterName}"); delegateMethodParameters.Add(parameterName); handled = true; break; } } if (handled) { continue; } methodParameterNamesWithTypes.Add($"{GetFriendlyName(parameterType, GetTypeName(options, originalType))} {parameterName}"); delegateMethodParameters.Add(parameterName); } }
private static void CreateConstructor(TypeToTypeWrapperOptions options, List <string> constructorParameterNames, List <string> constructorFielsNamesWithTypes, StringBuilder code, List <string> constructorParameterNamesWithTypes, Type originalType, Guid id) { if (constructorParameterNames?.Any() == true) { foreach (var fieldNameWithType in constructorFielsNamesWithTypes) { code.AppendLine($"private {fieldNameWithType};"); } code.AppendLine($"public {GetTypeName(options, originalType)}({string.Join(", ", constructorParameterNamesWithTypes)})"); code.AppendLine("{"); foreach (var constructorParameterName in constructorParameterNames) { code.AppendLine($"_{constructorParameterName} = {constructorParameterName};"); } code.AppendLine( $"Weikio.TypeGenerator.Types.TypeCache.Details(System.Guid.Parse(\"{id.ToString()}\")).OnConstructor.DynamicInvoke(_instance);"); if (options.OnConstructorCustomCodeGenerator != null) { code.AppendLine("// Custom constructor code begins"); code.AppendLine(options.OnConstructorCustomCodeGenerator(options, originalType)); code.AppendLine("// Custom constructor code ends"); } code.AppendLine("}"); // Close constructor } else if (options.OnConstructor != null) { code.AppendLine($"public {GetTypeName(options, originalType)}()"); code.AppendLine("{"); code.AppendLine( $"Weikio.TypeGenerator.Types.TypeCache.Details(System.Guid.Parse(\"{id.ToString()}\")).OnConstructor.DynamicInvoke(_instance);"); if (options.OnConstructorCustomCodeGenerator != null) { code.AppendLine("// Custom constructor code begins"); code.AppendLine(options.OnConstructorCustomCodeGenerator(options, originalType)); code.AppendLine("// Custom constructor code ends"); } code.AppendLine("}"); // Close constructor } else { code.AppendLine($"public {GetTypeName(options, originalType)}()"); code.AppendLine("{"); if (options.OnConstructorCustomCodeGenerator != null) { code.AppendLine("// Custom constructor code begins"); code.AppendLine(options.OnConstructorCustomCodeGenerator(options, originalType)); code.AppendLine("// Custom constructor code ends"); } code.AppendLine("}"); // Close constructor } }
private static void CreateWrapperMethod(TypeToTypeWrapperOptions options, Type returnType, StringBuilder code, List <string> methodParameterNamesWithTypes, Guid id, List <string> delegateMethodParameters, MethodInfo methodInfo, Type originalType) { var originalMethodName = methodInfo.Name; var generatedMethodName = options.MethodNameGenerator(options, originalType, methodInfo); if (typeof(void) != returnType) { code.AppendLine( $"public {GetFriendlyName(returnType, GetTypeName(options, originalType))} {generatedMethodName} ({string.Join(", ", methodParameterNamesWithTypes)})"); } else { code.AppendLine( $"public void {generatedMethodName} ({string.Join(", ", methodParameterNamesWithTypes)})"); } code.AppendLine("{"); if (options.OnBeforeMethod != null) { code.AppendLine( $"Weikio.TypeGenerator.Types.TypeCache.Details(System.Guid.Parse(\"{id.ToString()}\")).OnBeforeMethod.DynamicInvoke(_instance, _instance.GetType().GetMethod(\"{originalMethodName}\", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static));"); } if (options.OnBeforeMethodCustomCodeGenerator != null) { code.AppendLine("// Custom before method code begins"); code.AppendLine(options.OnBeforeMethodCustomCodeGenerator(options, originalType, methodInfo)); code.AppendLine("// Custom before method code ends"); } if (typeof(void) != returnType) { code.AppendLine( $"var result = ({GetFriendlyName(returnType, GetTypeName(options, originalType))}) _instance.{originalMethodName}({string.Join(", ", delegateMethodParameters)});"); } else { code.AppendLine($"_instance.{originalMethodName}({string.Join(", ", delegateMethodParameters)});"); } if (options.OnAfterMethod != null) { code.AppendLine( $"Weikio.TypeGenerator.Types.TypeCache.Details(System.Guid.Parse(\"{id.ToString()}\")).OnAfterMethod.DynamicInvoke(_instance, _instance.GetType().GetMethod(\"{originalMethodName}\", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static));"); } if (options.OnAfterMethodCustomCodeGenerator != null) { code.AppendLine("// Custom after method code begins"); code.AppendLine(options.OnAfterMethodCustomCodeGenerator(options, originalType, methodInfo)); code.AppendLine("// Custom after method code ends"); } if (typeof(void) != returnType) { code.AppendLine("return result;"); } code.AppendLine("}"); // Close method }
private void AddConstructorParameter(AdditionalParameter additionalConstructorParameter, List <string> constructorParameterNames, List <string> constructorParameterNamesWithTypes, List <string> constructorFieldNamesWithTypes, TypeToTypeWrapperOptions options, Type originalType) { constructorParameterNames.Add(additionalConstructorParameter.Name); constructorParameterNamesWithTypes.Add( $"{GetFriendlyName(additionalConstructorParameter.Type, GetTypeName(options, originalType))} {additionalConstructorParameter.Name}"); var fieldName = $"_{additionalConstructorParameter.Name}"; constructorFieldNamesWithTypes.Add($"{GetFriendlyName(additionalConstructorParameter.Type, GetTypeName(options, originalType))} {fieldName}"); }
public Type CreateType(Type originalType, TypeToTypeWrapperOptions options = default) { if (originalType == null) { throw new ArgumentNullException(nameof(originalType)); } if (options == null) { options = new TypeToTypeWrapperOptions(); } var methods = GetMethodsToWrap(originalType, options); var allTypes = new List <Type> { originalType }; foreach (var methodInfo in methods) { var parameters = methodInfo.GetParameters(); var returnType = methodInfo.ReturnType; var requiredTypesForMethod = GetRequiredTypes(parameters, returnType); foreach (var type in requiredTypesForMethod) { if (allTypes.Contains(type)) { continue; } allTypes.Add(type); } } var properties = GetPropertiesToWrap(originalType, options); foreach (var propertyInfo in properties) { var propertyType = propertyInfo.PropertyType; var requiredTypes = GetRequiredTypes(null, propertyType); foreach (var type in requiredTypes) { if (allTypes.Contains(type)) { continue; } allTypes.Add(type); } } var id = TypeCache.Add(originalType, options); AddReferences(options.AssemblyGenerator, allTypes, options, originalType); var code = new StringBuilder(); AddNamespaces(code, allTypes); var constructorParameterNames = new List <string>(); var constructorParameterNamesWithTypes = new List <string>(); var constructorFieldNamesWithTypes = new List <string>(); var propertyNamesWithTypes = new List <string>(); var conversionRules = options?.ConversionRules; if (conversionRules == null) { conversionRules = new List <ParameterConversionRule>(); } var d = new Dictionary <MethodInfo, (List <string>, List <string>)>(); foreach (var methodInfo in methods) { var parameters = methodInfo.GetParameters(); var methodParameterNamesWithTypes = new List <string>(); var delegateMethodParameters = new List <string>(); DoConversions(parameters, conversionRules, constructorParameterNames, constructorParameterNamesWithTypes, constructorFieldNamesWithTypes, propertyNamesWithTypes, delegateMethodParameters, methodParameterNamesWithTypes, options, originalType); d.Add(methodInfo, (delegateMethodParameters, methodParameterNamesWithTypes)); } if (options.AdditionalConstructorParameters?.Any() == true) { foreach (var additionalConstructorParameter in options.AdditionalConstructorParameters) { AddConstructorParameter(additionalConstructorParameter, constructorParameterNames, constructorParameterNamesWithTypes, constructorFieldNamesWithTypes, options, originalType); } } code.AppendLine(); code.AppendLine($"namespace {GetNamespace(options, originalType)}"); code.AppendLine("{"); var inheritedAndImplementedTypes = new List <Type>(); if (options.Inherits != null) { inheritedAndImplementedTypes.Add(options.Inherits); } if (options.Implements != null) { inheritedAndImplementedTypes.AddRange(options.Implements); } var inheritance = ""; if (inheritedAndImplementedTypes.Any()) { inheritance = $" : {string.Join(", ", inheritedAndImplementedTypes.Select(x => x.FullName))}"; } code.AppendLine($"public class {GetTypeName(options, originalType)} {inheritance}"); code.AppendLine("{"); CreateInstance(originalType, code, id); CreateConstructor(options, constructorParameterNames, constructorFieldNamesWithTypes, code, constructorParameterNamesWithTypes, originalType, id); CreateProperties(propertyNamesWithTypes, code); foreach (var methodInfo in methods) { var parameters = methodInfo.GetParameters(); var returnType = methodInfo.ReturnType; var p = d[methodInfo]; CreateWrapperMethod(options, returnType, code, p.Item2, id, p.Item1, methodInfo, originalType); } foreach (var propertyInfo in properties) { CreateWrapperProperty(options, code, propertyInfo, originalType); } if (options.CustomCodeGenerator != null) { code.AppendLine("// Custom code begins"); code.AppendLine(options.CustomCodeGenerator(options, originalType)); code.AppendLine("// Custom code ends"); } if (options.IsSourceCodeIncluded) { code.AppendLine("##sourceplaceholder##"); } code.AppendLine("}"); // Close class code.AppendLine("}"); // Close namespace var fullCode = code.ToString(); if (options.IsSourceCodePrettified) { fullCode = CSharpSyntaxTree.ParseText(fullCode).GetRoot().NormalizeWhitespace().ToFullString(); } if (options.IsSourceCodeIncluded) { code.AppendLine("// Source code begins"); fullCode = fullCode.Replace("##sourceplaceholder##", $"private string _source = @\"{Environment.NewLine}{fullCode.Replace("\"", "\"\"").Replace("##sourceplaceholder##", "")}\";"); code.AppendLine("// Source code ends"); } var assembly = options.AssemblyGenerator.GenerateAssembly(fullCode); var result = assembly.GetExportedTypes().Single(); return(result); }