Sprache.ParseException for async lambda inside of a method
Closed this issue ยท 8 comments
I stumbled upon what appears to be a bug, that can be reproduced with the following code. I am using version 3.4.1 in a netcoreapp3.1 application:
static void Main(string[] args)
{
new ConfigurationContainer().Create().Serialize(new Foo());
}
public class Foo
{
public string Bar { get; set; }
}
public interface ISomething { }
public class Something : ISomething
{
Func<ISomething, Task> Check<T>(Func<T, Task> data)
{
return async o => await data((T)o); // this causes it to bomb out
return o => data((T)o); // this works without issue
}
}
When the line
return async o => await data((T)o);
is used, the following error is generated:
Sprache.ParseException
HResult=0x80131500
Message=Parsing failure: unexpected '<'; expected letter (Line 1, Column 1); recently consumed:
Source=Sprache
StackTrace:
at Sprache.ParserExtensions.Parse[T](Parser`1 parser, String input)
at ExtendedXmlSerializer.ContentModel.Reflection.TypeNameFormatter.Format(TypeInfo type)
at ExtendedXmlSerializer.ContentModel.Reflection.TypeNameFormatter.Get(TypeInfo parameter)
at ExtendedXmlSerializer.Core.Sources.LinkedDecoratedSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.DecoratedSource`2.Get(TParameter parameter)
at System.Linq.Lookup`2.Create(IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
at System.Linq.Enumerable.ToLookup[TSource,TKey](IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
at System.Linq.Enumerable.ToLookup[TSource,TKey](IEnumerable`1 source, Func`2 keySelector)
at ExtendedXmlSerializer.ContentModel.Reflection.AssemblyTypePartitions.Format(IGrouping`2 grouping)
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector)
at ExtendedXmlSerializer.ContentModel.Reflection.AssemblyTypePartitions.Create(Assembly parameter)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
at ExtendedXmlSerializer.ContentModel.Reflection.AssemblyTypePartitions.Get(TypePartition parameter)
at ExtendedXmlSerializer.Core.Sources.FirstAssignedSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.ContentModel.Reflection.PartitionedTypeCandidates.Create(IIdentity parameter)
at ExtendedXmlSerializer.Core.Sources.StructureCacheBase`2.CreateStructure(TKey parameter)
at System.Runtime.CompilerServices.ConditionalWeakTable`2.GetValueLocked(TKey key, CreateValueCallback createValueCallback)
at System.Runtime.CompilerServices.ConditionalWeakTable`2.GetValue(TKey key, CreateValueCallback createValueCallback)
at ExtendedXmlSerializer.Core.Sources.StructureCacheBase`2.Get(TKey key)
at ExtendedXmlSerializer.ContentModel.Reflection.TypeCandidates.Get(IIdentity parameter)
at ExtendedXmlSerializer.ContentModel.Reflection.Types.Create(IIdentity parameter)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
at ExtendedXmlSerializer.ContentModel.Members.MemberSerializers.IsMember(IMember profile)
at ExtendedXmlSerializer.ContentModel.Members.MemberSerializers.Content(IMember profile, IMemberAccess access)
at ExtendedXmlSerializer.ContentModel.Members.MemberSerializers.Property(IConverter converter, IMember profile, IMemberAccess access)
at ExtendedXmlSerializer.ContentModel.Members.MemberSerializers.Get(IMember parameter)
at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at ExtendedXmlSerializer.ContentModel.Members.MemberSerializations.Create(TypeInfo parameter)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
at ExtendedXmlSerializer.ContentModel.Members.InstanceMemberSerialization..ctor(TypeInfo type, IMemberSerializations serializations)
at ExtendedXmlSerializer.ContentModel.Members.InstanceMemberSerializations.Get(TypeInfo parameter)
at ExtendedXmlSerializer.ContentModel.Members.MemberedContents.Get(TypeInfo parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.ContentModel.Content.RecursionAwareContents.Get(TypeInfo parameter)
at ExtendedXmlSerializer.ExtensionModel.Xml.CustomSerializationExtension.Contents.Get(TypeInfo parameter)
at ExtendedXmlSerializer.Core.Sources.Cache`2.Create(TKey parameter)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
at ExtendedXmlSerializer.ExtensionModel.References.DeferredContents.Get(TypeInfo parameter)
at ExtendedXmlSerializer.ContentModel.Content.Serializers.Get(TypeInfo parameter)
at ExtendedXmlSerializer.Core.Sources.CoercedParameter`3.Get(TFrom parameter)
at ExtendedXmlSerializer.Core.Sources.DelegatedSource`2.Get(TParameter parameter)
at ExtendedXmlSerializer.ExtensionModel.References.ReferenceAwareSerializers.Get(TypeInfo parameter)
at ExtendedXmlSerializer.ContentModel.Content.DynamicAwareSerializers.Get(TypeInfo parameter)
at ExtendedXmlSerializer.ExtensionModel.RootInstanceExtension.Serializers.Get(TypeInfo parameter)
at ExtendedXmlSerializer.Core.Sources.Cache`2.Create(TKey parameter)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
at ExtendedXmlSerializer.ExtensionMethodsForCoreSources.Get[T](IParameterizedSource`2 this, Type parameter)
at ExtendedXmlSerializer.ExtensionModel.Xml.Write.Execute(Writing parameter)
at ExtendedXmlSerializer.ExtensionModel.Xml.Serializer.Serialize(XmlWriter writer, Object instance)
at ExtendedXmlSerializer.ExtensionModel.ThreadProtectionExtension.Serializer.Serialize(XmlWriter writer, Object instance)
at ExtendedXmlSerializer.ExtensionModel.Xml.ExtendedXmlSerializer.Serialize(XmlWriter writer, Object instance)
at ExtendedXmlSerializer.ExtensionModel.Xml.InstanceFormatter.Get(Object parameter)
at ExtendedXmlSerializer.ExtensionMethodsForSerialization.Serialize(IExtendedXmlSerializer this, IXmlWriterFactory factory, Func`1 stream, Object instance)
at ExtendedXmlSerializer.ExtensionMethodsForSerialization.Serialize(IExtendedXmlSerializer this, Object instance)
at ExtendedXMLSerializer_Issue.Program.Main(String[] args) in C:\Users\woodrowp\Desktop\ExtendedXMLSerializer_Issue\Program.cs:line 19
The error is NOT thrown if the line is changed to:
return o => data((T)o);
Why is the serializer attempting to serialize a method of the class? I am not aware of any attributes that would allow the method to be ignored by the serializer.
The demo project for this is attached.
Issue Label Bot is not confident enough to auto-label this issue. See dashboard for more details.
Branch issues/fix/i470 created!
Doh, @pmwoodrow thank you for writing in and reporting this. I can confirm that this occurs with a test that I have created using the code you have provided. It appears that we are running into a problem with the type resolution code on container startup/initialization. I agree that this seems odd and totally unexpected that it is throwing on a method. I will see if I can get this situated and fixed for you sometime this weekend. ๐
FWIW it appears we can remove the interface and reduce it to the following:
[Fact]
public void Verify()
{
new ConfigurationContainer().Create().Serialize(new Foo());
}
public class Foo
{
public string Bar { get; set; }
}
public class Something
{
Func<object, Task> Check<T>(Func<T, Task> data)
{
return async o => await data((T)o); // this causes it to bomb out
}
}
@Mike-E-angelo, thanks for the quick response on this. I had a feeling that the interface was not important, given my testing identified the presence of the async/await to be the tipping point. I just wanted to make sure it was captured in the original post in case it had any bearing at all.
Alright @pmwoodrow looks like this is due to how the asynchronous state machine componentry is generated. We were already doing a check for the CompilerGeneratedAttribute
but apparently this is not applied to the asynchronous bits when it is generated by the compiler. ๐คทโโ๏ธ
So now we do a further, subsequent check for "unspeakable" types.
A build is here for you to check out and verify if it works better for your solution:
#471 (comment)
If this works well for you, we will deploy this to NuGet on Tuesday. โ
@Mike-E-angelo, thanks for the quick turn on a dev build. I can confirm that it resolves the issue in my application that was exhibiting issues with previous builds. Looks good to deploy to NuGet.
Alrighty, this has been deployed to NuGet:
https://www.nuget.org/packages/ExtendedXmlSerializer/
Please do let me know if you encounter any issues with this build and I will take a look into it for you. Thank you for improving ExtendedXmlSerializer! Closing for now.
An extensible Xml Serializer for .NET that builds on the functionality of the classic XmlSerializer with a powerful and robust extension model.