diff --git a/src/ConfigurationProcessor.Core/IConfigurationProcessor.cs b/src/ConfigurationProcessor.Core/IConfigurationProcessor.cs
new file mode 100644
index 0000000..64a03c9
--- /dev/null
+++ b/src/ConfigurationProcessor.Core/IConfigurationProcessor.cs
@@ -0,0 +1,26 @@
+// -------------------------------------------------------------------------------------------------
+// Copyright (c) almostchristian. All rights reserved.
+// -------------------------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ConfigurationProcessor
+{
+ ///
+ /// Represents a configuration helper for dynamically executing methods.
+ ///
+ public interface IConfigurationProcessor
+ {
+ ///
+ /// Invokes a specificed configuration method with specificed arguments. Method is chosen based on the argument types.
+ ///
+ ///
+ ///
+ ///
+ ///
+ void Invoke(T instance, string methodName, params object[] arguments)
+ where T : class;
+ }
+}
diff --git a/src/ConfigurationProcessor.Core/Implementation/ConfigurationHelperImplementation.cs b/src/ConfigurationProcessor.Core/Implementation/ConfigurationHelperImplementation.cs
new file mode 100644
index 0000000..b80d95e
--- /dev/null
+++ b/src/ConfigurationProcessor.Core/Implementation/ConfigurationHelperImplementation.cs
@@ -0,0 +1,50 @@
+// -------------------------------------------------------------------------------------------------
+// Copyright (c) almostchristian. All rights reserved.
+// -------------------------------------------------------------------------------------------------
+
+using System;
+using System.Linq;
+using System.Reflection;
+using Microsoft.Extensions.Configuration;
+
+namespace ConfigurationProcessor.Core.Implementation
+{
+ internal class ConfigurationHelperImplementation : IConfigurationProcessor
+ {
+ private readonly ResolutionContext resolutionContext;
+ private readonly IConfigurationSection configurationSection;
+ private readonly ConfigurationReaderOptions? options;
+
+ public ConfigurationHelperImplementation(ResolutionContext resolutionContext, IConfigurationSection configurationSection, ConfigurationReaderOptions? options)
+ {
+ this.resolutionContext = resolutionContext;
+ this.configurationSection = configurationSection;
+ this.options = options;
+ }
+
+ public void Invoke(T instance, string methodName, params object[] arguments)
+ where T : class
+ {
+ resolutionContext.CallConfigurationMethod(
+ typeof(T),
+ methodName,
+ configurationSection,
+ null,
+ Array.Empty(),
+ null!,
+ () => arguments.ToList(),
+ (arguments, methodInfo) =>
+ {
+ if (methodInfo.IsStatic)
+ {
+ arguments.Insert(0, instance);
+ methodInfo.Invoke(null, arguments.ToArray());
+ }
+ else
+ {
+ methodInfo.Invoke(instance, arguments.ToArray());
+ }
+ });
+ }
+ }
+}
diff --git a/src/ConfigurationProcessor.Core/Implementation/ConfigurationReader{TConfig}.cs b/src/ConfigurationProcessor.Core/Implementation/ConfigurationReader{TConfig}.cs
index acec799..e02b31d 100644
--- a/src/ConfigurationProcessor.Core/Implementation/ConfigurationReader{TConfig}.cs
+++ b/src/ConfigurationProcessor.Core/Implementation/ConfigurationReader{TConfig}.cs
@@ -23,10 +23,11 @@ public void AddServices(TConfig builder, string? sectionName, bool getChildren,
var builderDirective = string.IsNullOrEmpty(sectionName) ? ConfigurationSection : ConfigurationSection.GetSection(sectionName);
if (!getChildren || builderDirective.GetChildren().Any())
{
- var methodCalls = ResolutionContext.GetMethodCalls(builderDirective, getChildren);
ResolutionContext.CallConfigurationMethods(
typeof(TConfig),
- methodCalls,
+ builderDirective,
+ getChildren,
+ null,
options.MethodFilterFactory,
(arguments, methodInfo) =>
{
diff --git a/src/ConfigurationProcessor.Core/Implementation/Extensions.cs b/src/ConfigurationProcessor.Core/Implementation/Extensions.cs
index 66a116a..4606e6a 100644
--- a/src/ConfigurationProcessor.Core/Implementation/Extensions.cs
+++ b/src/ConfigurationProcessor.Core/Implementation/Extensions.cs
@@ -25,191 +25,229 @@ internal static class Extensions
private const char GenericTypeMarker = '`';
private const char GenericTypeParameterSeparator = '|';
- public static void CallConfigurationMethods(
- this ResolutionContext resolutionContext,
- Type extensionArgumentType,
- ILookup methods,
- MethodFilterFactory? methodFilterFactory,
- Action, MethodInfo> invoker)
+ public static void CallConfigurationMethod(
+ this ResolutionContext resolutionContext,
+ Type extensionArgumentType,
+ string methodName,
+ IConfigurationSection configSection,
+ MethodFilterFactory? methodFilterFactory,
+ TypeResolver[] typeArgs,
+ Dictionary? paramArgs,
+ Func>? argumentFactory,
+ Action, MethodInfo> invoker)
{
- foreach (var (methodName, (typeArgs, configSection, configArgs)) in methods.SelectMany(g => g.Select(x => (MethodName: g.Key, Config: x))))
+ methodFilterFactory ??= MethodFilterFactories.DefaultMethodFilterFactory;
+
+ var (methodFilter, candidateNames) = methodFilterFactory(methodName);
+ IEnumerable configurationMethods = resolutionContext
+ .FindConfigurationExtensionMethods(methodName, extensionArgumentType, typeArgs, candidateNames, methodFilter);
+ configurationMethods = configurationMethods.Union(resolutionContext.AdditionalMethods.Where(m => candidateNames.Contains(m.Name) && methodFilter(m, methodName))).ToList();
+
+ var suppliedArgumentNames = paramArgs?.Keys.ToArray() ?? Array.Empty();
+
+ var isCollection = suppliedArgumentNames.IsArray();
+ MethodInfo? configurationMethod;
+
+ var args = argumentFactory?.Invoke();
+
+ if (isCollection)
{
- var paramArgs = configArgs;
- methodFilterFactory ??= MethodFilterFactories.DefaultMethodFilterFactory;
+ configurationMethod = configurationMethods
+ .Where(m =>
+ {
+ var parameters = m.GetParameters();
+ if (parameters.Length != (m.IsStatic ? 2 : 1))
+ {
+ return false;
+ }
- var (methodFilter, candidateNames) = methodFilterFactory(methodName);
- IEnumerable configurationMethods = resolutionContext
- .FindConfigurationExtensionMethods(methodName, extensionArgumentType, typeArgs, candidateNames, methodFilter);
- configurationMethods = configurationMethods.Union(resolutionContext.AdditionalMethods.Where(m => candidateNames.Contains(m.Name) && methodFilter(m, methodName))).ToList();
- var suppliedArgumentNames = paramArgs.Keys;
+ var paramType = parameters[m.IsStatic ? 1 : 0].ParameterType;
+ var isCollection = paramType.IsArray || (paramType.IsGenericType && typeof(List<>) == paramType.GetGenericTypeDefinition());
- var isCollection = suppliedArgumentNames.IsArray();
- MethodInfo? configurationMethod;
- if (isCollection)
- {
- configurationMethod = configurationMethods
- .Where(m =>
+ if (isCollection)
{
- var parameters = m.GetParameters();
- if (parameters.Length != (m.IsStatic ? 2 : 1))
+#pragma warning disable CA1031 // Do not catch general exception types
+ try
+ {
+#pragma warning disable S1481 // Unused local variables should be removed
+ var collection = GetCollection(resolutionContext, configSection!, m);
+#pragma warning restore S1481 // Unused local variables should be removed
+ }
+ catch
{
return false;
}
+#pragma warning restore CA1031 // Do not catch general exception types
+ }
- var paramType = parameters[m.IsStatic ? 1 : 0].ParameterType;
- var isCollection = paramType.IsArray || (paramType.IsGenericType && typeof(List<>) == paramType.GetGenericTypeDefinition());
+ return isCollection;
+ })
+ .SingleOrDefault($"Ambiguous match while searching for a method that accepts a list or array.");
+ }
+ else
+ {
+ // for single property, choose the best configuration method by attempting to convert the parameter value
+ if (suppliedArgumentNames.Length == 1 && string.IsNullOrEmpty(suppliedArgumentNames.Single()) && configSection.Value != null)
+ {
+ var argvalue = configSection.Value;
+ configurationMethod = configurationMethods
+ .Where(m =>
+ {
+ var parameters = m.GetParameters();
+ System.Diagnostics.Debug.WriteLine(parameters.Count(p => !p.HasDefaultValue));
+ if (parameters.Count(p => !p.HasDefaultValue && !p.HasImplicitValueWhenNotSpecified()) != (m.IsStatic ? 2 : 1))
+ {
+ return false;
+ }
+
+ var paramType = m.GetParameters().Where(p => !p.HasImplicitValueWhenNotSpecified()).ElementAt(m.IsStatic ? 1 : 0).ParameterType;
+ var isCollection = paramType.IsArray || (paramType.IsGenericType && typeof(List<>) == paramType.GetGenericTypeDefinition());
+ if (isCollection)
+ {
+ return false;
+ }
- if (isCollection)
- {
#pragma warning disable CA1031 // Do not catch general exception types
- try
- {
-#pragma warning disable S1481 // Unused local variables should be removed
- var collection = GetCollection(m);
-#pragma warning restore S1481 // Unused local variables should be removed
- }
- catch
- {
- return false;
- }
+ try
+ {
+ var argValue = new StringArgumentValue(configSection, argvalue);
+ argValue.ConvertTo(m, paramType, resolutionContext);
+
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
#pragma warning restore CA1031 // Do not catch general exception types
- }
+ })
+ .SingleOrDefault($"Ambiguous match while searching for a method that accepts a single value.") ??
- return isCollection;
- })
- .SingleOrDefault($"Ambiguous match while searching for a method that accepts a list or array.");
+ // if no match found, choose the parameterless overload
+ configurationMethods.SingleOrDefault(m => m.GetParameters().Count(p => !p.HasDefaultValue) == (m.IsStatic ? 1 : 0));
+ }
+ else if (args != null)
+ {
+ configurationMethod = configurationMethods.SelectConfigurationMethod(args.Select(a => a.GetType()));
}
else
{
- // for single property, choose the best configuration method by attempting to convert the parameter value
- if (suppliedArgumentNames.Count == 1 && string.IsNullOrEmpty(suppliedArgumentNames.Single()) && configSection.Value != null)
- {
- var argvalue = configSection.Value;
- configurationMethod = configurationMethods
- .Where(m =>
- {
- var parameters = m.GetParameters();
- System.Diagnostics.Debug.WriteLine(parameters.Count(p => !p.HasDefaultValue));
- if (parameters.Count(p => !p.HasDefaultValue) != (m.IsStatic ? 2 : 1))
- {
- return false;
- }
-
- var paramType = m.GetParameters().ElementAt(m.IsStatic ? 1 : 0).ParameterType;
- var isCollection = paramType.IsArray || (paramType.IsGenericType && typeof(List<>) == paramType.GetGenericTypeDefinition());
- if (isCollection)
- {
- return false;
- }
+ configurationMethod = configurationMethods.SelectConfigurationMethod(suppliedArgumentNames);
+ }
-#pragma warning disable CA1031 // Do not catch general exception types
- try
- {
- var argValue = new StringArgumentValue(configSection, argvalue);
- argValue.ConvertTo(m, paramType, resolutionContext);
-
- return true;
- }
- catch
- {
- return false;
- }
-#pragma warning restore CA1031 // Do not catch general exception types
- })
- .SingleOrDefault($"Ambiguous match while searching for a method that accepts a single value.") ??
+ if (configurationMethod == null)
+ {
+ // if the method could still not be found, look method that accepts a single dictionary
+ configurationMethod = configurationMethods
+ .Where(m =>
+ {
+ var parameters = m.GetParameters();
+ if (parameters.Length != (m.IsStatic ? 2 : 1))
+ {
+ return false;
+ }
- // if no match found, choose the parameterless overload
- configurationMethods.SingleOrDefault(m => m.GetParameters().Count(p => !p.HasDefaultValue) == (m.IsStatic ? 1 : 0));
- }
- else
- {
- configurationMethod = configurationMethods.SelectConfigurationMethod(suppliedArgumentNames);
- }
+ var paramType = parameters[m.IsStatic ? 1 : 0].ParameterType;
+ return paramType.IsGenericType && typeof(Dictionary<,>) == paramType.GetGenericTypeDefinition();
+ })
+ .SingleOrDefault($"Ambigous match while searching for a method that accepts Dictionary<,>.");
- if (configurationMethod == null)
+ if (configurationMethod != null)
{
- // if the method could still not be found, look method that accepts a single dictionary
- configurationMethod = configurationMethods
- .Where(m =>
- {
- var parameters = m.GetParameters();
- if (parameters.Length != (m.IsStatic ? 2 : 1))
- {
- return false;
- }
-
- var paramType = parameters[m.IsStatic ? 1 : 0].ParameterType;
- return paramType.IsGenericType && typeof(Dictionary<,>) == paramType.GetGenericTypeDefinition();
- })
- .SingleOrDefault($"Ambigous match while searching for a method that accepts Dictionary<,>.");
-
- if (configurationMethod != null)
- {
- paramArgs = new Dictionary
+ paramArgs = new Dictionary
{
{ string.Empty, (new ObjectArgumentValue(configSection), configSection) },
};
- }
}
}
+ }
- IEnumerable? GetCollection(MethodInfo method)
+ if (configurationMethod != null)
+ {
+ if (argumentFactory != null && args != null)
{
- var argValue = new ObjectArgumentValue(configSection!);
- var collectionType = method.GetParameters().ElementAt(method.IsStatic ? 1 : 0).ParameterType;
- return argValue.ConvertTo(method, collectionType, resolutionContext) as ICollection;
+ invoker(args, configurationMethod);
}
-
- if (configurationMethod != null)
+ else if (isCollection)
{
- if (isCollection)
- {
- var collection = GetCollection(configurationMethod);
- invoker(new List