serilog-settings-configuration
serilog-settings-configuration copied to clipboard
Add support for delegates values in StringArgumentValue
Some sinks contain configuration properties/arguments that are delegate types (Action
, Func
).
The StringArgumentValue
class already supports static field and property accessors for non-delegate types, and can be extended to support delegate values that are accessed from static properties, static fields or static non-generic methods. If the argument value points to a method, overload resolution should be done to match the target delegate with the reflected method.
A disadvantage could be that this would encourage the creation of static methods which some view as bad for testability.
Below is my proposed change:
if (TryParseStaticMemberAccessor(argumentValue, out var accessorTypeName, out var memberName))
{
var accessorType = Type.GetType(accessorTypeName, throwOnError: true);
// if target type is a delegate, look for a public static non-generic method in the accessor type
if (typeof(Delegate).IsAssignableFrom(toType))
{
var methodCandidates = accessorType.GetTypeInfo().DeclaredMethods
.Where(x => x.Name == memberName)
.Where(x => x.IsPublic)
.Where(x => !x.IsGenericMethod)
.Where(x => x.IsStatic)
.ToList();
// if more than 1 candidates, get target type signature and perform overload resolution on candidate methods
if (methodCandidates.Count > 1)
{
var delegateSig = toType.GetMethod("Invoke");
var delegateParameters = delegateSig.GetParameters().Select(x => x.ParameterType);
methodCandidates = methodCandidates
.Where(x => x.ReturnType == delegateSig.ReturnType)
.Where(x => x.GetParameters().Select(p => p.ParameterType).SequenceEqual(delegateParameters))
.ToList();
}
var method = methodCandidates.SingleOrDefault();
if (method != null)
{
return method.CreateDelegate(toType);
}
I guess this would solve my issue with Elasticsearch sink, in which I need to set a Func<,>
delegate to option ModifyConnectionSettings
but I couldn't find a way to do this.
Great, do it!