diff --git a/src/ExtendedXmlSerializer/ContentModel/Identification/IdentityStore.cs b/src/ExtendedXmlSerializer/ContentModel/Identification/IdentityStore.cs index 8a558acf..1c6e1850 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Identification/IdentityStore.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Identification/IdentityStore.cs @@ -1,5 +1,5 @@ -using System; using ExtendedXmlSerializer.Core.Sources; +using System; namespace ExtendedXmlSerializer.ContentModel.Identification { @@ -7,8 +7,7 @@ sealed class IdentityStore : Cache>, IIdentitySt { public IdentityStore() : base(i => new Names(i).Get) {} - public IIdentity Get(string name, string identifier) => Get(identifier) - .Invoke(name); + public IIdentity Get(string name, string identifier) => Get(identifier).Invoke(name); sealed class Names : CacheBase { diff --git a/src/ExtendedXmlSerializer/ContentModel/Reflection/TypePartReflector.cs b/src/ExtendedXmlSerializer/ContentModel/Reflection/TypePartReflector.cs index a185e4c0..92bb9bb8 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Reflection/TypePartReflector.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Reflection/TypePartReflector.cs @@ -1,56 +1,63 @@ -using System; -using System.Collections.Immutable; -using System.Reflection; using ExtendedXmlSerializer.ContentModel.Conversion; using ExtendedXmlSerializer.ContentModel.Identification; using ExtendedXmlSerializer.Core.Sources; using Sprache; +using System; +using System.Collections.Immutable; +using System.Reflection; -namespace ExtendedXmlSerializer.ContentModel.Reflection +namespace ExtendedXmlSerializer.ContentModel.Reflection; + +sealed class TypePartReflector : CacheBase, ITypePartReflector { - sealed class TypePartReflector : CacheBase, ITypePartReflector + readonly IIdentityStore _identities; + readonly ITypes _types; + + public TypePartReflector(IIdentityStore identities, ITypes types) : base(TypePartsEqualityComparer.Default) { - readonly IIdentityStore _identities; - readonly ITypes _types; + _identities = identities; + _types = types; + } - public TypePartReflector(IIdentityStore identities, ITypes types) : base(TypePartsEqualityComparer.Default) - { - _identities = identities; - _types = types; - } + protected override TypeInfo Create(TypeParts parameter) + { + var identity = _identities.Get(parameter.Name, parameter.Identifier); + var typeInfo = _types.Get(identity); + var arguments = parameter.GetArguments(); + var type = (arguments.HasValue ? Generic(typeInfo, arguments.Value) : typeInfo) + ?? + throw new + ParseException($"An attempt was made to parse the identity '{IdentityFormatter.Default.Get(identity)}', but no type could be located with that name."); + var result = parameter.Dimensions.HasValue + ? new DimensionsAlteration(parameter.Dimensions.Value).Get(type) + : type; + return result; + } - protected override TypeInfo Create(TypeParts parameter) - { - var identity = _identities.Get(parameter.Name, parameter.Identifier); - var typeInfo = _types.Get(identity); - var arguments = parameter.GetArguments(); - var type = arguments.HasValue - ? typeInfo.MakeGenericType(Arguments(arguments.Value)) - .GetTypeInfo() - : typeInfo; - if (type == null) - { - throw new ParseException( - $"An attempt was made to parse the identity '{IdentityFormatter.Default.Get(identity)}', but no type could be located with that name."); - } - - var result = parameter.Dimensions.HasValue - ? new DimensionsAlteration(parameter.Dimensions.Value).Get(type) - : type; - return result; - } + TypeInfo Generic(TypeInfo candidate, ImmutableArray arguments) + { + var definition = candidate.Name.EndsWith($"`{arguments.Length}") + ? candidate + : Locate(candidate, arguments.Length); + return definition.MakeGenericType(Arguments(arguments)).GetTypeInfo(); + } - Type[] Arguments(ImmutableArray names) + static Type Locate(TypeInfo candidate, int count) + { + var original = candidate.FullName; + var name = $"{original.Split('`')[0]}`{count}"; + return candidate.Assembly.GetType(name, true); + } + + Type[] Arguments(ImmutableArray names) + { + var length = names.Length; + var result = new Type[length]; + for (var i = 0; i < length; i++) { - var length = names.Length; - var result = new Type[length]; - for (var i = 0; i < length; i++) - { - result[i] = Get(names[i]) - .AsType(); - } - - return result; + result[i] = Get(names[i]); } + + return result; } } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ContentModel/Reflection/Types.cs b/src/ExtendedXmlSerializer/ContentModel/Reflection/Types.cs index 9cfc13cf..63545e48 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Reflection/Types.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Reflection/Types.cs @@ -11,7 +11,6 @@ sealed class Types : CacheBase, ITypes readonly ITypeIdentities _aliased; readonly ITypeCandidates _candidates; - // ReSharper disable once TooManyDependencies [UsedImplicitly] public Types(IPartitionedTypeSpecification specification, IAssemblyTypePartitions partitions, @@ -25,6 +24,6 @@ public Types(IPartitionedTypeSpecification specification, IAssemblyTypePartition } protected override TypeInfo Create(IIdentity parameter) - => _aliased.Get(parameter) ?? _candidates.Get(parameter).SingleOrDefault(); + => _aliased.Get(parameter) ?? _candidates.Get(parameter).FirstOrDefault(); } } \ No newline at end of file diff --git a/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue644Tests.cs b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue644Tests.cs new file mode 100644 index 00000000..43364218 --- /dev/null +++ b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue644Tests.cs @@ -0,0 +1,60 @@ +using ExtendedXmlSerializer.Configuration; +using ExtendedXmlSerializer.Tests.ReportedIssues.Support; +using FluentAssertions; +using Xunit; + +namespace ExtendedXmlSerializer.Tests.ReportedIssues; + +public sealed class Issue644Tests +{ + [Fact] + public void VerifySingle() + { + var sut = new ConfigurationContainer().EnableAllConstructors() + .UseAutoFormatting() + .EnableClassicListNaming() + .UseOptimizedNamespaces() + .AllowMultipleReferences() + .EnableXmlText() + .Create() + .ForTesting(); + var instance = new ObjectContainer + { + Object = new IssueClass { value = 2 } + }; + sut.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyDouble() + { + var sut = new ConfigurationContainer().EnableAllConstructors() + .UseAutoFormatting() + .EnableClassicListNaming() + .UseOptimizedNamespaces() + .AllowMultipleReferences() + .EnableXmlText() + .Create() + .ForTesting(); + var instance = new ObjectContainer + { + Object = new IssueClass { value = 2, other = "Hello world!" } + }; + sut.Cycle(instance).Should().BeEquivalentTo(instance); + } + + public class ObjectContainer + { + public object Object { get; set; } + } + + public class IssueClass + { + public T value; + } + + public class IssueClass : IssueClass + { + public U other; + } +} \ No newline at end of file diff --git a/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue645Tests.cs b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue645Tests.cs new file mode 100644 index 00000000..6d18ad93 --- /dev/null +++ b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue645Tests.cs @@ -0,0 +1,35 @@ +using ExtendedXmlSerializer.Configuration; +using ExtendedXmlSerializer.Tests.ReportedIssues.Support; +using FluentAssertions; +using System; +using System.Runtime.CompilerServices; +using Xunit; + +namespace ExtendedXmlSerializer.Tests.ReportedIssues +{ + public sealed class Issue645Tests + { + +#if CORE + [Fact] + public void VerifyTupleContainer() + { + var sut = new ConfigurationContainer().EnableParameterizedContent().Create().ForTesting(); + var instance = new TupleContainer { Subject = Tuple.Create(123) }; + sut.Cycle(instance).Should().BeEquivalentTo(instance); + } + + public class TupleContainer + { + public ITuple Subject { get; set; } + } +#endif + [Fact] + public void VerifyTuple() + { + var sut = new ConfigurationContainer().EnableParameterizedContent().Create().ForTesting(); + var instance = Tuple.Create(123); + sut.Cycle(instance).Should().BeEquivalentTo(instance); + } + } +}