Skip to content

Commit a14b22d

Browse files
Add support for delegate values serilog#259
1 parent b46a5f9 commit a14b22d

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,43 @@ public object ConvertTo(Type toType, ResolutionContext resolutionContext)
7171
TryParseStaticMemberAccessor(argumentValue, out var accessorTypeName, out var memberName))
7272
{
7373
var accessorType = Type.GetType(accessorTypeName, throwOnError: true);
74+
75+
// if delegate, look for a method and then construct a delegate
76+
if (typeof(Delegate).IsAssignableFrom(toType) || typeof(MethodInfo) == toType)
77+
{
78+
var methodCandidates = accessorType.GetTypeInfo().DeclaredMethods
79+
.Where(x => x.Name == memberName)
80+
.Where(x => x.IsPublic)
81+
.Where(x => !x.IsGenericMethod)
82+
.Where(x => x.IsStatic)
83+
.ToList();
84+
85+
if (methodCandidates.Count > 1 && typeof(Delegate).IsAssignableFrom(toType))
86+
{
87+
// filter possible method overloads
88+
89+
var delegateSig = toType.GetMethod("Invoke");
90+
var delegateParameters = delegateSig!.GetParameters().Select(x => x.ParameterType);
91+
methodCandidates = methodCandidates
92+
.Where(x => x.ReturnType == delegateSig.ReturnType && x.GetParameters().Select(y => y.ParameterType).SequenceEqual(delegateParameters))
93+
.ToList();
94+
}
95+
96+
var methodCandidate = methodCandidates.SingleOrDefault();
97+
98+
if (methodCandidate != null)
99+
{
100+
if (typeof(MethodInfo) == toType)
101+
{
102+
return methodCandidate;
103+
}
104+
else
105+
{
106+
return methodCandidate.CreateDelegate(toType);
107+
}
108+
}
109+
}
110+
74111
// is there a public static property with that name ?
75112
var publicStaticPropertyInfo = accessorType.GetTypeInfo().DeclaredProperties
76113
.Where(x => x.Name == memberName)

test/Serilog.Settings.Configuration.Tests/StringArgumentValueTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,22 @@ public void StaticMembersAccessorsCanBeUsedForAbstractTypes(string input, Type t
9999
Assert.Equal(ConcreteImpl.Instance, actual);
100100
}
101101

102+
[Theory]
103+
[InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::FuncIntParseField, Serilog.Settings.Configuration.Tests", typeof(Func<string, int>))]
104+
[InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::NamedIntParseField, Serilog.Settings.Configuration.Tests", typeof(NamedIntParse))]
105+
[InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::FuncIntParseProperty, Serilog.Settings.Configuration.Tests", typeof(Func<string, int>))]
106+
[InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::NamedIntParseProperty, Serilog.Settings.Configuration.Tests", typeof(NamedIntParse))]
107+
[InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::IntParseMethod, Serilog.Settings.Configuration.Tests", typeof(NamedIntParse))]
108+
[InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::IntParseMethod, Serilog.Settings.Configuration.Tests", typeof(Func<string, int>))]
109+
public void StaticMembersAccessorsCanBeUsedForDelegateTypes(string input, Type targetType)
110+
{
111+
var stringArgumentValue = new StringArgumentValue(input);
112+
113+
var actual = stringArgumentValue.ConvertTo(targetType, new ResolutionContext());
114+
115+
Assert.IsAssignableFrom(targetType, actual);
116+
}
117+
102118
[Theory]
103119
[InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::ConcreteClassProperty, Serilog.Settings.Configuration.Tests", typeof(AConcreteClass))]
104120
[InlineData("Serilog.Settings.Configuration.Tests.Support.ClassWithStaticAccessors::ConcreteClassField, Serilog.Settings.Configuration.Tests", typeof(AConcreteClass))]

test/Serilog.Settings.Configuration.Tests/Support/StaticAccessorClasses.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
namespace Serilog.Settings.Configuration.Tests.Support
1+
using System;
2+
3+
namespace Serilog.Settings.Configuration.Tests.Support
24
{
5+
public delegate int NamedIntParse(string value);
6+
37
public interface IAmAnInterface
48
{
59
}
@@ -46,5 +50,11 @@ public class ClassWithStaticAccessors
4650
#pragma warning restore 169
4751
public IAmAnInterface InstanceInterfaceProperty => ConcreteImpl.Instance;
4852
public IAmAnInterface InstanceInterfaceField = ConcreteImpl.Instance;
53+
54+
public static Func<string, int> FuncIntParseField = int.Parse;
55+
public static NamedIntParse NamedIntParseField = int.Parse;
56+
public static Func<string, int> FuncIntParseProperty => int.Parse;
57+
public static NamedIntParse NamedIntParseProperty => int.Parse;
58+
public static int IntParseMethod(string value) => int.Parse(value);
4959
}
5060
}

0 commit comments

Comments
 (0)