diff --git a/src/Serilog/Parameters/PropertyValueConverter.cs b/src/Serilog/Parameters/PropertyValueConverter.cs index b0eca3a6c..55dbe009f 100644 --- a/src/Serilog/Parameters/PropertyValueConverter.cs +++ b/src/Serilog/Parameters/PropertyValueConverter.cs @@ -25,6 +25,8 @@ #if NET40 using Serilog.Platform; +#else +using System.Runtime.CompilerServices; #endif namespace Serilog.Parameters @@ -154,9 +156,12 @@ LogEventPropertyValue CreatePropertyValue(object value, Destructuring destructur if (destructuring == Destructuring.Destructure) { - var typeTag = value.GetType().Name; - if (typeTag.Length <= 0 || !char.IsLetter(typeTag[0])) + var type = value.GetType(); + var typeTag = type.Name; + if (typeTag.Length <= 0 || IsCompilerGeneratedType(type)) + { typeTag = null; + } return new StructureValue(GetProperties(value, limiter), typeTag); } @@ -214,5 +219,19 @@ static IEnumerable GetProperties(object value, ILogEventProper yield return new LogEventProperty(prop.Name, recursive.CreatePropertyValue(propValue, true)); } } + +#if !NET40 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + internal static bool IsCompilerGeneratedType(Type type) + { + var typeInfo = type.GetTypeInfo(); + var typeName = type.Name; + + //C# Anonymous types always start with "<>" and VB's start with "VB$" + return typeInfo.IsGenericType && typeInfo.IsSealed && typeInfo.IsNotPublic && type.Namespace == null + && (typeName[0] == '<' + || (typeName.Length > 2 && typeName[0] == 'V' && typeName[1] == 'B' && typeName[2] == '$')); + } } } diff --git a/src/Serilog/Platform/TypeInfo-net40.cs b/src/Serilog/Platform/TypeInfo-net40.cs index c894edbcd..136d469e2 100644 --- a/src/Serilog/Platform/TypeInfo-net40.cs +++ b/src/Serilog/Platform/TypeInfo-net40.cs @@ -55,6 +55,8 @@ public TypeInfo(Type type) public IEnumerable DeclaredProperties => Type.GetProperties(); public bool IsAssignableFrom(TypeInfo targetType) => Type.IsAssignableFrom(targetType.Type); + + public bool IsNotPublic => Type.IsNotPublic; } } #endif diff --git a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs index 57a0d7a17..4fca562ad 100644 --- a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs +++ b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs @@ -234,6 +234,16 @@ public void ItemPropertiesNotAreIgnoredWhenDestructuring() var item = pv.Properties.Single(); Assert.Equal("Item", item.Name); } + + [Fact] + public void CSharpAnonymousTypesAreRecognizedWhenDestructuring() + { + var o = new { Foo = "Bar" }; + var result = _converter.CreatePropertyValue(o, true); + Assert.Equal(typeof(StructureValue), result.GetType()); + var structuredValue = (StructureValue)result; + Assert.Equal(null, structuredValue.TypeTag); + } } }