Skip to content

Commit

Permalink
Support setting values of interface types where a fully-qualified typ…
Browse files Browse the repository at this point in the history
…e name is supplied
  • Loading branch information
nblumhardt committed Jun 20, 2016
1 parent b758729 commit 67bfa3f
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 8 deletions.
40 changes: 32 additions & 8 deletions src/Serilog/Settings/KeyValuePairs/KeyValuePairSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Serilog.Configuration;
using Serilog.Events;
Expand Down Expand Up @@ -155,6 +157,12 @@ internal static IEnumerable<Assembly> LoadConfigurationAssemblies(Dictionary<str
return configurationAssemblies.Distinct();
}

static Dictionary<Type, Func<string, object>> ExtendedTypeConversions = new Dictionary<Type, Func<string, object>>
{
{ typeof(Uri), s => new Uri(s) },
{ typeof(TimeSpan), s => TimeSpan.Parse(s) }
};

internal static object ConvertToType(string value, Type toType)
{
var toTypeInfo = toType.GetTypeInfo();
Expand All @@ -171,18 +179,34 @@ internal static object ConvertToType(string value, Type toType)
if (toTypeInfo.IsEnum)
return Enum.Parse(toType, value);

var extendedTypeConversions = new Dictionary<Type, Func<string, object>>
{
{ typeof(Uri), s => new Uri(s) },
{ typeof(TimeSpan), s => TimeSpan.Parse(s) }
};

var convertor = extendedTypeConversions
var convertor = ExtendedTypeConversions
.Where(t => t.Key.GetTypeInfo().IsAssignableFrom(toTypeInfo))
.Select(t => t.Value)
.FirstOrDefault();

return convertor == null ? Convert.ChangeType(value, toType) : convertor(value);
if (convertor != null)
return convertor(value);

if (toTypeInfo.IsInterface && !string.IsNullOrWhiteSpace(value))
{
var type = Type.GetType(value.Trim(), throwOnError: false).GetTypeInfo();
if (type != null)
{
var ctor = type.DeclaredConstructors.FirstOrDefault(ci =>
{
var parameters = ci.GetParameters();
return parameters.Length == 0 || parameters.All(pi => pi.HasDefaultValue);
});

if (ctor == null)
throw new InvalidOperationException($"A default constructor was not found on {type.FullName}.");

var call = ctor.GetParameters().Select(pi => pi.DefaultValue).ToArray();
return ctor.Invoke(call);
}
}

return Convert.ChangeType(value, toType);
}

internal static IList<MethodInfo> FindSinkConfigurationMethods(IEnumerable<Assembly> configurationAssemblies)
Expand Down
11 changes: 11 additions & 0 deletions test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
using Serilog.Tests.Support;
using Serilog.Enrichers;
using TestDummies;
using Serilog.Formatting;
using Serilog.Formatting.Json;
using Serilog.Tests.Formatting.Json;

namespace Serilog.Tests.AppSettings.Tests
{
Expand Down Expand Up @@ -91,5 +94,13 @@ public void PropertyEnrichmentIsApplied()
Assert.NotNull(evt);
Assert.Equal("Test", evt.Properties["App"].LiteralValue());
}


[Fact]
public void StringValuesConvertToDefaultInstancesIfTargetIsInterface()
{
var result = (object)KeyValuePairSettings.ConvertToType("Serilog.Formatting.Json.JsonFormatter", typeof(ITextFormatter));
Assert.IsType<JsonFormatter>(result);
}
}
}

0 comments on commit 67bfa3f

Please sign in to comment.