From c39baa00efc763febfb86046238a14a7d67df7cf Mon Sep 17 00:00:00 2001 From: Rolf Kristensen Date: Mon, 10 Jun 2019 18:27:04 +0200 Subject: [PATCH] LogLevel - Added support for TypeConverter --- src/NLog/Attributes/LogLevelTypeConverter.cs | 69 +++++++++++++++++++ src/NLog/Internal/ObjectReflectionCache.cs | 4 +- src/NLog/LogLevel.cs | 8 ++- src/NLog/NLog.csproj | 1 + .../LayoutRenderers/LogLevelTests.cs | 7 +- 5 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 src/NLog/Attributes/LogLevelTypeConverter.cs diff --git a/src/NLog/Attributes/LogLevelTypeConverter.cs b/src/NLog/Attributes/LogLevelTypeConverter.cs new file mode 100644 index 0000000000..3b68e02716 --- /dev/null +++ b/src/NLog/Attributes/LogLevelTypeConverter.cs @@ -0,0 +1,69 @@ +namespace NLog.Attributes +{ + using System; + using System.ComponentModel; + using System.Globalization; + + /// + /// Support implementation of + /// + public class LogLevelTypeConverter : TypeConverter + { + /// + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return IsSupportedType(sourceType) || base.CanConvertFrom(context, sourceType); + } + + /// + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + TypeCode casted = Convert.GetTypeCode(value); + switch (casted) + { + case TypeCode.String: + return LogLevel.FromString(value.ToString()); + case TypeCode.Int16: + return LogLevel.FromOrdinal(Convert.ToInt16(value)); + case TypeCode.UInt16: + return LogLevel.FromOrdinal(Convert.ToUInt16(value)); + case TypeCode.Int32: + return LogLevel.FromOrdinal(Convert.ToInt32(value)); + case TypeCode.UInt32: + return LogLevel.FromOrdinal((int)Convert.ToUInt32(value)); + case TypeCode.Int64: + return LogLevel.FromOrdinal((int)Convert.ToInt64(value)); + case TypeCode.UInt64: + return LogLevel.FromOrdinal((int)Convert.ToUInt64(value)); + default: + return base.ConvertFrom(context, culture, value); + } + } + + /// + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return IsSupportedType(destinationType) || base.CanConvertTo(context, destinationType); + } + + /// + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + var casted = value as LogLevel; + return destinationType == typeof(string) && casted != null + ? casted.ToString() + : base.ConvertTo(context, culture, casted?.Ordinal ?? value, destinationType); + } + + private static bool IsSupportedType(Type sourceType) + { + return sourceType == typeof(string) || + sourceType == typeof(short) || + sourceType == typeof(ushort) || + sourceType == typeof(int) || + sourceType == typeof(uint) || + sourceType == typeof(long) || + sourceType == typeof(ulong); + } + } +} \ No newline at end of file diff --git a/src/NLog/Internal/ObjectReflectionCache.cs b/src/NLog/Internal/ObjectReflectionCache.cs index 14a87749e5..38ae9e3de1 100644 --- a/src/NLog/Internal/ObjectReflectionCache.cs +++ b/src/NLog/Internal/ObjectReflectionCache.cs @@ -99,7 +99,7 @@ public ObjectPropertyList LookupObjectProperties(object value) private static ObjectPropertyInfos BuildObjectPropertyInfos(object value, Type objectType) { ObjectPropertyInfos propertyInfos; - if (ConvertToString(objectType)) + if (ConvertSimpleToString(objectType)) { propertyInfos = ObjectPropertyInfos.SimpleToString; } @@ -125,7 +125,7 @@ private static ObjectPropertyInfos BuildObjectPropertyInfos(object value, Type o return propertyInfos; } - private static bool ConvertToString(Type objectType) + private static bool ConvertSimpleToString(Type objectType) { if (objectType == typeof(Guid)) return true; diff --git a/src/NLog/LogLevel.cs b/src/NLog/LogLevel.cs index c582f2f7c7..9f115ce5f8 100644 --- a/src/NLog/LogLevel.cs +++ b/src/NLog/LogLevel.cs @@ -35,11 +35,12 @@ namespace NLog { using System; using System.Collections.Generic; - using NLog.Internal; + using System.ComponentModel; /// /// Defines available log levels. /// + [TypeConverter(typeof(Attributes.LogLevelTypeConverter))] public sealed class LogLevel : IComparable, IEquatable, IConvertible { /// @@ -464,7 +465,10 @@ string IConvertible.ToString(IFormatProvider provider) object IConvertible.ToType(Type conversionType, IFormatProvider provider) { - return Convert.ChangeType(_ordinal, conversionType, provider); + if (conversionType == typeof(string)) + return Name; + else + return Convert.ChangeType(_ordinal, conversionType, provider); } ushort IConvertible.ToUInt16(IFormatProvider provider) diff --git a/src/NLog/NLog.csproj b/src/NLog/NLog.csproj index 67eca4ca86..d7e9ebd395 100644 --- a/src/NLog/NLog.csproj +++ b/src/NLog/NLog.csproj @@ -293,6 +293,7 @@ For all config options and platform support, check https://nlog-project.org/conf + diff --git a/tests/NLog.UnitTests/LayoutRenderers/LogLevelTests.cs b/tests/NLog.UnitTests/LayoutRenderers/LogLevelTests.cs index a34e46c2f2..3937c950d6 100644 --- a/tests/NLog.UnitTests/LayoutRenderers/LogLevelTests.cs +++ b/tests/NLog.UnitTests/LayoutRenderers/LogLevelTests.cs @@ -132,16 +132,19 @@ public void LogLevelGetTypeCodeTest() [Theory] [InlineData(typeof(int), 2)] [InlineData(typeof(uint), (uint)2)] + [InlineData(typeof(string), "Info")] public void LogLevelConvertTest(Type type, object expected) { // Arrange var logLevel = LogLevel.Info; // Act - var result = Convert.ChangeType(logLevel, type); + var changeToResult = Convert.ChangeType(logLevel, type); + var changeFromResult = System.ComponentModel.TypeDescriptor.GetConverter(typeof(LogLevel)).ConvertFrom(changeToResult); // Assert - Assert.Equal(expected, result); + Assert.Equal(expected, changeToResult); + Assert.Equal(logLevel, changeFromResult); } } } \ No newline at end of file